• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "rsdCore.h"
18 #include "rsdBcc.h"
19 #include "rsdRuntime.h"
20 
21 #include <bcinfo/MetadataExtractor.h>
22 
23 #include "rsContext.h"
24 #include "rsElement.h"
25 #include "rsScriptC.h"
26 
27 #include "utils/Timers.h"
28 #include "utils/StopWatch.h"
29 
30 using namespace android;
31 using namespace android::renderscript;
32 
33 struct DrvScript {
34     int (*mRoot)();
35     int (*mRootExpand)();
36     void (*mInit)();
37     void (*mFreeChildren)();
38 
39     BCCScriptRef mBccScript;
40 
41     bcinfo::MetadataExtractor *ME;
42 
43     InvokeFunc_t *mInvokeFunctions;
44     ForEachFunc_t *mForEachFunctions;
45     void ** mFieldAddress;
46     bool * mFieldIsObject;
47     const uint32_t *mExportForEachSignatureList;
48 
49     const uint8_t * mScriptText;
50     uint32_t mScriptTextLength;
51 };
52 
53 typedef void (*outer_foreach_t)(
54     const android::renderscript::RsForEachStubParamStruct *,
55     uint32_t x1, uint32_t x2,
56     uint32_t instep, uint32_t outstep);
57 
setTLS(Script * sc)58 static Script * setTLS(Script *sc) {
59     ScriptTLSStruct * tls = (ScriptTLSStruct *)pthread_getspecific(rsdgThreadTLSKey);
60     rsAssert(tls);
61     Script *old = tls->mScript;
62     tls->mScript = sc;
63     return old;
64 }
65 
66 
rsdScriptInit(const Context * rsc,ScriptC * script,char const * resName,char const * cacheDir,uint8_t const * bitcode,size_t bitcodeSize,uint32_t flags)67 bool rsdScriptInit(const Context *rsc,
68                      ScriptC *script,
69                      char const *resName,
70                      char const *cacheDir,
71                      uint8_t const *bitcode,
72                      size_t bitcodeSize,
73                      uint32_t flags) {
74     //ALOGE("rsdScriptCreate %p %p %p %p %i %i %p", rsc, resName, cacheDir, bitcode, bitcodeSize, flags, lookupFunc);
75 
76     pthread_mutex_lock(&rsdgInitMutex);
77 
78     size_t exportFuncCount = 0;
79     size_t exportVarCount = 0;
80     size_t objectSlotCount = 0;
81     size_t exportForEachSignatureCount = 0;
82 
83     const char* coreLib = "/system/lib/libclcore.bc";
84     bcinfo::RSFloatPrecision prec;
85 
86     DrvScript *drv = (DrvScript *)calloc(1, sizeof(DrvScript));
87     if (drv == NULL) {
88         goto error;
89     }
90     script->mHal.drv = drv;
91 
92     drv->mBccScript = bccCreateScript();
93     script->mHal.info.isThreadable = true;
94     drv->mScriptText = bitcode;
95     drv->mScriptTextLength = bitcodeSize;
96 
97 
98     drv->ME = new bcinfo::MetadataExtractor((const char*)drv->mScriptText,
99                                             drv->mScriptTextLength);
100     if (!drv->ME->extract()) {
101       ALOGE("bcinfo: failed to read script metadata");
102       goto error;
103     }
104 
105     //ALOGE("mBccScript %p", script->mBccScript);
106 
107     if (bccRegisterSymbolCallback(drv->mBccScript, &rsdLookupRuntimeStub, script) != 0) {
108         ALOGE("bcc: FAILS to register symbol callback");
109         goto error;
110     }
111 
112     if (bccReadBC(drv->mBccScript,
113                   resName,
114                   (char const *)drv->mScriptText,
115                   drv->mScriptTextLength, 0) != 0) {
116         ALOGE("bcc: FAILS to read bitcode");
117         goto error;
118     }
119 
120     // NEON-capable devices can use an accelerated math library for all
121     // reduced precision scripts.
122 #if defined(ARCH_ARM_HAVE_NEON)
123     prec = drv->ME->getRSFloatPrecision();
124     if (prec != bcinfo::RS_FP_Full) {
125         coreLib = "/system/lib/libclcore_neon.bc";
126     }
127 #endif
128 
129     if (bccLinkFile(drv->mBccScript, coreLib, 0) != 0) {
130         ALOGE("bcc: FAILS to link bitcode");
131         goto error;
132     }
133 
134     if (bccPrepareExecutable(drv->mBccScript, cacheDir, resName, 0) != 0) {
135         ALOGE("bcc: FAILS to prepare executable");
136         goto error;
137     }
138 
139     drv->mRoot = reinterpret_cast<int (*)()>(bccGetFuncAddr(drv->mBccScript, "root"));
140     drv->mRootExpand = reinterpret_cast<int (*)()>(bccGetFuncAddr(drv->mBccScript, "root.expand"));
141     drv->mInit = reinterpret_cast<void (*)()>(bccGetFuncAddr(drv->mBccScript, "init"));
142     drv->mFreeChildren = reinterpret_cast<void (*)()>(bccGetFuncAddr(drv->mBccScript, ".rs.dtor"));
143 
144     exportFuncCount = drv->ME->getExportFuncCount();
145     if (exportFuncCount > 0) {
146         drv->mInvokeFunctions = (InvokeFunc_t*) calloc(exportFuncCount,
147                                                        sizeof(InvokeFunc_t));
148         bccGetExportFuncList(drv->mBccScript, exportFuncCount,
149                              (void **) drv->mInvokeFunctions);
150     } else {
151         drv->mInvokeFunctions = NULL;
152     }
153 
154     exportVarCount = drv->ME->getExportVarCount();
155     if (exportVarCount > 0) {
156         drv->mFieldAddress = (void **) calloc(exportVarCount, sizeof(void*));
157         drv->mFieldIsObject = (bool *) calloc(exportVarCount, sizeof(bool));
158         bccGetExportVarList(drv->mBccScript, exportVarCount,
159                             (void **) drv->mFieldAddress);
160     } else {
161         drv->mFieldAddress = NULL;
162         drv->mFieldIsObject = NULL;
163     }
164 
165     objectSlotCount = drv->ME->getObjectSlotCount();
166     if (objectSlotCount > 0) {
167         const uint32_t *objectSlotList = drv->ME->getObjectSlotList();
168         for (uint32_t ct=0; ct < objectSlotCount; ct++) {
169             drv->mFieldIsObject[objectSlotList[ct]] = true;
170         }
171     }
172 
173     exportForEachSignatureCount = drv->ME->getExportForEachSignatureCount();
174     drv->mExportForEachSignatureList = drv->ME->getExportForEachSignatureList();
175     if (exportForEachSignatureCount > 0) {
176         drv->mForEachFunctions =
177             (ForEachFunc_t*) calloc(exportForEachSignatureCount,
178                                     sizeof(ForEachFunc_t));
179         bccGetExportForEachList(drv->mBccScript, exportForEachSignatureCount,
180                                 (void **) drv->mForEachFunctions);
181     } else {
182         drv->mForEachFunctions = NULL;
183     }
184 
185     // Copy info over to runtime
186     script->mHal.info.exportedFunctionCount = drv->ME->getExportFuncCount();
187     script->mHal.info.exportedVariableCount = drv->ME->getExportVarCount();
188     script->mHal.info.exportedPragmaCount = drv->ME->getPragmaCount();
189     script->mHal.info.exportedPragmaKeyList = drv->ME->getPragmaKeyList();
190     script->mHal.info.exportedPragmaValueList = drv->ME->getPragmaValueList();
191 
192     if (drv->mRootExpand) {
193       script->mHal.info.root = drv->mRootExpand;
194     } else {
195       script->mHal.info.root = drv->mRoot;
196     }
197 
198     pthread_mutex_unlock(&rsdgInitMutex);
199     return true;
200 
201 error:
202 
203     pthread_mutex_unlock(&rsdgInitMutex);
204     if (drv->ME) {
205         delete drv->ME;
206         drv->ME = NULL;
207     }
208     free(drv);
209     return false;
210 
211 }
212 
213 typedef struct {
214     Context *rsc;
215     Script *script;
216     ForEachFunc_t kernel;
217     uint32_t sig;
218     const Allocation * ain;
219     Allocation * aout;
220     const void * usr;
221     size_t usrLen;
222 
223     uint32_t mSliceSize;
224     volatile int mSliceNum;
225 
226     const uint8_t *ptrIn;
227     uint32_t eStrideIn;
228     uint8_t *ptrOut;
229     uint32_t eStrideOut;
230 
231     uint32_t yStrideIn;
232     uint32_t yStrideOut;
233 
234     uint32_t xStart;
235     uint32_t xEnd;
236     uint32_t yStart;
237     uint32_t yEnd;
238     uint32_t zStart;
239     uint32_t zEnd;
240     uint32_t arrayStart;
241     uint32_t arrayEnd;
242 
243     uint32_t dimX;
244     uint32_t dimY;
245     uint32_t dimZ;
246     uint32_t dimArray;
247 } MTLaunchStruct;
248 typedef void (*rs_t)(const void *, void *, const void *, uint32_t, uint32_t, uint32_t, uint32_t);
249 
wc_xy(void * usr,uint32_t idx)250 static void wc_xy(void *usr, uint32_t idx) {
251     MTLaunchStruct *mtls = (MTLaunchStruct *)usr;
252     RsForEachStubParamStruct p;
253     memset(&p, 0, sizeof(p));
254     p.usr = mtls->usr;
255     p.usr_len = mtls->usrLen;
256     RsdHal * dc = (RsdHal *)mtls->rsc->mHal.drv;
257     uint32_t sig = mtls->sig;
258 
259     outer_foreach_t fn = (outer_foreach_t) mtls->kernel;
260     while (1) {
261         uint32_t slice = (uint32_t)android_atomic_inc(&mtls->mSliceNum);
262         uint32_t yStart = mtls->yStart + slice * mtls->mSliceSize;
263         uint32_t yEnd = yStart + mtls->mSliceSize;
264         yEnd = rsMin(yEnd, mtls->yEnd);
265         if (yEnd <= yStart) {
266             return;
267         }
268 
269         //ALOGE("usr idx %i, x %i,%i  y %i,%i", idx, mtls->xStart, mtls->xEnd, yStart, yEnd);
270         //ALOGE("usr ptr in %p,  out %p", mtls->ptrIn, mtls->ptrOut);
271         for (p.y = yStart; p.y < yEnd; p.y++) {
272             p.out = mtls->ptrOut + (mtls->yStrideOut * p.y);
273             p.in = mtls->ptrIn + (mtls->yStrideIn * p.y);
274             fn(&p, mtls->xStart, mtls->xEnd, mtls->eStrideIn, mtls->eStrideOut);
275         }
276     }
277 }
278 
wc_x(void * usr,uint32_t idx)279 static void wc_x(void *usr, uint32_t idx) {
280     MTLaunchStruct *mtls = (MTLaunchStruct *)usr;
281     RsForEachStubParamStruct p;
282     memset(&p, 0, sizeof(p));
283     p.usr = mtls->usr;
284     p.usr_len = mtls->usrLen;
285     RsdHal * dc = (RsdHal *)mtls->rsc->mHal.drv;
286     uint32_t sig = mtls->sig;
287 
288     outer_foreach_t fn = (outer_foreach_t) mtls->kernel;
289     while (1) {
290         uint32_t slice = (uint32_t)android_atomic_inc(&mtls->mSliceNum);
291         uint32_t xStart = mtls->xStart + slice * mtls->mSliceSize;
292         uint32_t xEnd = xStart + mtls->mSliceSize;
293         xEnd = rsMin(xEnd, mtls->xEnd);
294         if (xEnd <= xStart) {
295             return;
296         }
297 
298         //ALOGE("usr slice %i idx %i, x %i,%i", slice, idx, xStart, xEnd);
299         //ALOGE("usr ptr in %p,  out %p", mtls->ptrIn, mtls->ptrOut);
300 
301         p.out = mtls->ptrOut + (mtls->eStrideOut * xStart);
302         p.in = mtls->ptrIn + (mtls->eStrideIn * xStart);
303         fn(&p, xStart, xEnd, mtls->eStrideIn, mtls->eStrideOut);
304     }
305 }
306 
rsdScriptInvokeForEach(const Context * rsc,Script * s,uint32_t slot,const Allocation * ain,Allocation * aout,const void * usr,uint32_t usrLen,const RsScriptCall * sc)307 void rsdScriptInvokeForEach(const Context *rsc,
308                             Script *s,
309                             uint32_t slot,
310                             const Allocation * ain,
311                             Allocation * aout,
312                             const void * usr,
313                             uint32_t usrLen,
314                             const RsScriptCall *sc) {
315 
316     RsdHal * dc = (RsdHal *)rsc->mHal.drv;
317 
318     MTLaunchStruct mtls;
319     memset(&mtls, 0, sizeof(mtls));
320 
321     DrvScript *drv = (DrvScript *)s->mHal.drv;
322     mtls.kernel = drv->mForEachFunctions[slot];
323     rsAssert(mtls.kernel != NULL);
324     mtls.sig = 0x1f;  // temp fix for old apps, full table in slang_rs_export_foreach.cpp
325     if (drv->mExportForEachSignatureList) {
326         mtls.sig = drv->mExportForEachSignatureList[slot];
327     }
328     if (ain) {
329         mtls.dimX = ain->getType()->getDimX();
330         mtls.dimY = ain->getType()->getDimY();
331         mtls.dimZ = ain->getType()->getDimZ();
332         //mtls.dimArray = ain->getType()->getDimArray();
333     } else if (aout) {
334         mtls.dimX = aout->getType()->getDimX();
335         mtls.dimY = aout->getType()->getDimY();
336         mtls.dimZ = aout->getType()->getDimZ();
337         //mtls.dimArray = aout->getType()->getDimArray();
338     } else {
339         rsc->setError(RS_ERROR_BAD_SCRIPT, "rsForEach called with null allocations");
340         return;
341     }
342 
343     if (!sc || (sc->xEnd == 0)) {
344         mtls.xEnd = mtls.dimX;
345     } else {
346         rsAssert(sc->xStart < mtls.dimX);
347         rsAssert(sc->xEnd <= mtls.dimX);
348         rsAssert(sc->xStart < sc->xEnd);
349         mtls.xStart = rsMin(mtls.dimX, sc->xStart);
350         mtls.xEnd = rsMin(mtls.dimX, sc->xEnd);
351         if (mtls.xStart >= mtls.xEnd) return;
352     }
353 
354     if (!sc || (sc->yEnd == 0)) {
355         mtls.yEnd = mtls.dimY;
356     } else {
357         rsAssert(sc->yStart < mtls.dimY);
358         rsAssert(sc->yEnd <= mtls.dimY);
359         rsAssert(sc->yStart < sc->yEnd);
360         mtls.yStart = rsMin(mtls.dimY, sc->yStart);
361         mtls.yEnd = rsMin(mtls.dimY, sc->yEnd);
362         if (mtls.yStart >= mtls.yEnd) return;
363     }
364 
365     mtls.xEnd = rsMax((uint32_t)1, mtls.xEnd);
366     mtls.yEnd = rsMax((uint32_t)1, mtls.yEnd);
367     mtls.zEnd = rsMax((uint32_t)1, mtls.zEnd);
368     mtls.arrayEnd = rsMax((uint32_t)1, mtls.arrayEnd);
369 
370     rsAssert(!ain || (ain->getType()->getDimZ() == 0));
371 
372     Context *mrsc = (Context *)rsc;
373     Script * oldTLS = setTLS(s);
374 
375     mtls.rsc = mrsc;
376     mtls.ain = ain;
377     mtls.aout = aout;
378     mtls.script = s;
379     mtls.usr = usr;
380     mtls.usrLen = usrLen;
381     mtls.mSliceSize = 10;
382     mtls.mSliceNum = 0;
383 
384     mtls.ptrIn = NULL;
385     mtls.eStrideIn = 0;
386     if (ain) {
387         mtls.ptrIn = (const uint8_t *)ain->getPtr();
388         mtls.eStrideIn = ain->getType()->getElementSizeBytes();
389         mtls.yStrideIn = ain->mHal.drvState.stride;
390     }
391 
392     mtls.ptrOut = NULL;
393     mtls.eStrideOut = 0;
394     if (aout) {
395         mtls.ptrOut = (uint8_t *)aout->getPtr();
396         mtls.eStrideOut = aout->getType()->getElementSizeBytes();
397         mtls.yStrideOut = aout->mHal.drvState.stride;
398     }
399 
400     if ((dc->mWorkers.mCount > 1) && s->mHal.info.isThreadable && !dc->mInForEach) {
401         dc->mInForEach = true;
402         if (mtls.dimY > 1) {
403             rsdLaunchThreads(mrsc, wc_xy, &mtls);
404         } else {
405             rsdLaunchThreads(mrsc, wc_x, &mtls);
406         }
407         dc->mInForEach = false;
408 
409         //ALOGE("launch 1");
410     } else {
411         RsForEachStubParamStruct p;
412         memset(&p, 0, sizeof(p));
413         p.usr = mtls.usr;
414         p.usr_len = mtls.usrLen;
415         uint32_t sig = mtls.sig;
416 
417         //ALOGE("launch 3");
418         outer_foreach_t fn = (outer_foreach_t) mtls.kernel;
419         for (p.ar[0] = mtls.arrayStart; p.ar[0] < mtls.arrayEnd; p.ar[0]++) {
420             for (p.z = mtls.zStart; p.z < mtls.zEnd; p.z++) {
421                 for (p.y = mtls.yStart; p.y < mtls.yEnd; p.y++) {
422                     uint32_t offset = mtls.dimX * mtls.dimY * mtls.dimZ * p.ar[0] +
423                                       mtls.dimX * mtls.dimY * p.z +
424                                       mtls.dimX * p.y;
425                     p.out = mtls.ptrOut + (mtls.eStrideOut * offset);
426                     p.in = mtls.ptrIn + (mtls.eStrideIn * offset);
427                     fn(&p, mtls.xStart, mtls.xEnd, mtls.eStrideIn,
428                        mtls.eStrideOut);
429                 }
430             }
431         }
432     }
433 
434     setTLS(oldTLS);
435 }
436 
437 
rsdScriptInvokeRoot(const Context * dc,Script * script)438 int rsdScriptInvokeRoot(const Context *dc, Script *script) {
439     DrvScript *drv = (DrvScript *)script->mHal.drv;
440 
441     Script * oldTLS = setTLS(script);
442     int ret = drv->mRoot();
443     setTLS(oldTLS);
444 
445     return ret;
446 }
447 
rsdScriptInvokeInit(const Context * dc,Script * script)448 void rsdScriptInvokeInit(const Context *dc, Script *script) {
449     DrvScript *drv = (DrvScript *)script->mHal.drv;
450 
451     if (drv->mInit) {
452         drv->mInit();
453     }
454 }
455 
rsdScriptInvokeFreeChildren(const Context * dc,Script * script)456 void rsdScriptInvokeFreeChildren(const Context *dc, Script *script) {
457     DrvScript *drv = (DrvScript *)script->mHal.drv;
458 
459     if (drv->mFreeChildren) {
460         drv->mFreeChildren();
461     }
462 }
463 
rsdScriptInvokeFunction(const Context * dc,Script * script,uint32_t slot,const void * params,size_t paramLength)464 void rsdScriptInvokeFunction(const Context *dc, Script *script,
465                             uint32_t slot,
466                             const void *params,
467                             size_t paramLength) {
468     DrvScript *drv = (DrvScript *)script->mHal.drv;
469     //ALOGE("invoke %p %p %i %p %i", dc, script, slot, params, paramLength);
470 
471     Script * oldTLS = setTLS(script);
472     ((void (*)(const void *, uint32_t))
473         drv->mInvokeFunctions[slot])(params, paramLength);
474     setTLS(oldTLS);
475 }
476 
rsdScriptSetGlobalVar(const Context * dc,const Script * script,uint32_t slot,void * data,size_t dataLength)477 void rsdScriptSetGlobalVar(const Context *dc, const Script *script,
478                            uint32_t slot, void *data, size_t dataLength) {
479     DrvScript *drv = (DrvScript *)script->mHal.drv;
480     //rsAssert(!script->mFieldIsObject[slot]);
481     //ALOGE("setGlobalVar %p %p %i %p %i", dc, script, slot, data, dataLength);
482 
483     int32_t *destPtr = ((int32_t **)drv->mFieldAddress)[slot];
484     if (!destPtr) {
485         //ALOGV("Calling setVar on slot = %i which is null", slot);
486         return;
487     }
488 
489     memcpy(destPtr, data, dataLength);
490 }
491 
rsdScriptSetGlobalVarWithElemDims(const android::renderscript::Context * dc,const android::renderscript::Script * script,uint32_t slot,void * data,size_t dataLength,const android::renderscript::Element * elem,const size_t * dims,size_t dimLength)492 void rsdScriptSetGlobalVarWithElemDims(
493         const android::renderscript::Context *dc,
494         const android::renderscript::Script *script,
495         uint32_t slot, void *data, size_t dataLength,
496         const android::renderscript::Element *elem,
497         const size_t *dims, size_t dimLength) {
498     DrvScript *drv = (DrvScript *)script->mHal.drv;
499 
500     int32_t *destPtr = ((int32_t **)drv->mFieldAddress)[slot];
501     if (!destPtr) {
502         //ALOGV("Calling setVar on slot = %i which is null", slot);
503         return;
504     }
505 
506     // We want to look at dimension in terms of integer components,
507     // but dimLength is given in terms of bytes.
508     dimLength /= sizeof(int);
509 
510     // Only a single dimension is currently supported.
511     rsAssert(dimLength == 1);
512     if (dimLength == 1) {
513         // First do the increment loop.
514         size_t stride = elem->getSizeBytes();
515         char *cVal = reinterpret_cast<char *>(data);
516         for (size_t i = 0; i < dims[0]; i++) {
517             elem->incRefs(cVal);
518             cVal += stride;
519         }
520 
521         // Decrement loop comes after (to prevent race conditions).
522         char *oldVal = reinterpret_cast<char *>(destPtr);
523         for (size_t i = 0; i < dims[0]; i++) {
524             elem->decRefs(oldVal);
525             oldVal += stride;
526         }
527     }
528 
529     memcpy(destPtr, data, dataLength);
530 }
531 
rsdScriptSetGlobalBind(const Context * dc,const Script * script,uint32_t slot,void * data)532 void rsdScriptSetGlobalBind(const Context *dc, const Script *script, uint32_t slot, void *data) {
533     DrvScript *drv = (DrvScript *)script->mHal.drv;
534     //rsAssert(!script->mFieldIsObject[slot]);
535     //ALOGE("setGlobalBind %p %p %i %p", dc, script, slot, data);
536 
537     int32_t *destPtr = ((int32_t **)drv->mFieldAddress)[slot];
538     if (!destPtr) {
539         //ALOGV("Calling setVar on slot = %i which is null", slot);
540         return;
541     }
542 
543     memcpy(destPtr, &data, sizeof(void *));
544 }
545 
rsdScriptSetGlobalObj(const Context * dc,const Script * script,uint32_t slot,ObjectBase * data)546 void rsdScriptSetGlobalObj(const Context *dc, const Script *script, uint32_t slot, ObjectBase *data) {
547     DrvScript *drv = (DrvScript *)script->mHal.drv;
548     //rsAssert(script->mFieldIsObject[slot]);
549     //ALOGE("setGlobalObj %p %p %i %p", dc, script, slot, data);
550 
551     int32_t *destPtr = ((int32_t **)drv->mFieldAddress)[slot];
552     if (!destPtr) {
553         //ALOGV("Calling setVar on slot = %i which is null", slot);
554         return;
555     }
556 
557     rsrSetObject(dc, script, (ObjectBase **)destPtr, data);
558 }
559 
rsdScriptDestroy(const Context * dc,Script * script)560 void rsdScriptDestroy(const Context *dc, Script *script) {
561     DrvScript *drv = (DrvScript *)script->mHal.drv;
562 
563     if (drv->mFieldAddress) {
564         size_t exportVarCount = drv->ME->getExportVarCount();
565         for (size_t ct = 0; ct < exportVarCount; ct++) {
566             if (drv->mFieldIsObject[ct]) {
567                 // The field address can be NULL if the script-side has
568                 // optimized the corresponding global variable away.
569                 if (drv->mFieldAddress[ct]) {
570                     rsrClearObject(dc, script, (ObjectBase **)drv->mFieldAddress[ct]);
571                 }
572             }
573         }
574         free(drv->mFieldAddress);
575         drv->mFieldAddress = NULL;
576         free(drv->mFieldIsObject);
577         drv->mFieldIsObject = NULL;    }
578 
579     if (drv->mInvokeFunctions) {
580         free(drv->mInvokeFunctions);
581         drv->mInvokeFunctions = NULL;
582     }
583 
584     if (drv->mForEachFunctions) {
585         free(drv->mForEachFunctions);
586         drv->mForEachFunctions = NULL;
587     }
588 
589     delete drv->ME;
590     drv->ME = NULL;
591 
592     free(drv);
593     script->mHal.drv = NULL;
594 
595 }
596 
597 
598