blob: cf841949ffc05d81b6aef9a92d0a69f2fdd6f8c8 [file] [log] [blame]
Zonr Changccc39a82012-04-05 10:44:53 +08001/*
2 * Copyright 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 "Script.h"
18
19#include <errno.h>
20#include <sys/stat.h>
21#include <sys/types.h>
22#include <unistd.h>
23
24#include <new>
25#include <cstring>
26
27#include <llvm/ADT/STLExtras.h>
28
29#include <cutils/properties.h>
30
31#include "Config.h"
32
33#include "MCCacheReader.h"
34#include "MCCacheWriter.h"
35#include "CompilerOption.h"
36
37#include "DebugHelper.h"
Zonr Chang4f94c522012-04-05 15:09:28 +080038#include "FileMutex.h"
Zonr Changccc39a82012-04-05 10:44:53 +080039#include "GDBJITRegistrar.h"
Zonr Chang4f94c522012-04-05 15:09:28 +080040#include "InputFile.h"
41#include "OutputFile.h"
Zonr Changccc39a82012-04-05 10:44:53 +080042#include "ScriptCompiled.h"
43#include "ScriptCached.h"
44#include "Sha1Helper.h"
45#include "Source.h"
46
47namespace {
48
49bool getBooleanProp(const char *str) {
50 char buf[PROPERTY_VALUE_MAX];
51 property_get(str, buf, "0");
52 return strcmp(buf, "0") != 0;
53}
54
55} // namespace anonymous
56
57namespace bcc {
58
Zonr Chang1e2adce2012-04-12 13:29:43 +080059RSScript::SourceDependency::SourceDependency(const std::string &pSourceName,
Zonr Changccc39a82012-04-05 10:44:53 +080060 const uint8_t *pSHA1)
Zonr Chang1e2adce2012-04-12 13:29:43 +080061 : mSourceName(pSourceName) {
Zonr Changccc39a82012-04-05 10:44:53 +080062 ::memcpy(mSHA1, pSHA1, sizeof(mSHA1));
63 return;
64}
65
66RSScript::RSScript(Source &pSource)
67 : Script(pSource),
68 mpExtSymbolLookupFn(NULL),
69 mpExtSymbolLookupFnContext(NULL) {
70 resetState();
71 return;
72}
73
74RSScript::~RSScript() {
75 switch (mStatus) {
76 case ScriptStatus::Compiled:
77 delete mCompiled;
78 break;
79
80 case ScriptStatus::Cached:
81 delete mCached;
82 break;
83
84 default:
85 break;
86 }
87 llvm::DeleteContainerPointers(mSourceDependencies);
88}
89
90void RSScript::resetState() {
91 mErrorCode = BCC_NO_ERROR;
92 mStatus = ScriptStatus::Unknown;
93 mObjectType = ScriptObject::Unknown;
94 mIsContextSlotNotAvail = false;
95 // FIXME: mpExtSymbolLookupFn and mpExtSymbolLookupFnContext should be assign
96 // to NULL during state resetting.
97 //mpExtSymbolLookupFn = NULL;
98 //mpExtSymbolLookupFnContext = NULL;
99 llvm::DeleteContainerPointers(mSourceDependencies);
100 return;
101}
102
Zonr Changccc39a82012-04-05 10:44:53 +0800103bool RSScript::doReset() {
104 resetState();
105 return true;
106}
107
Zonr Chang1e2adce2012-04-12 13:29:43 +0800108bool RSScript::addSourceDependency(const std::string &pSourceName,
Zonr Changccc39a82012-04-05 10:44:53 +0800109 const uint8_t *pSHA1) {
110 SourceDependency *source_dep =
Zonr Chang1e2adce2012-04-12 13:29:43 +0800111 new (std::nothrow) SourceDependency(pSourceName, pSHA1);
Zonr Changccc39a82012-04-05 10:44:53 +0800112 if (source_dep == NULL) {
113 ALOGE("Out of memory when record dependency information of `%s'!",
114 pSourceName.c_str());
115 return false;
116 }
117
118 mSourceDependencies.push_back(source_dep);
119 return true;
120}
121
122int RSScript::prepareRelocatable(char const *objPath,
123 llvm::Reloc::Model RelocModel,
124 unsigned long flags) {
125 CompilerOption option;
126 option.RelocModelOpt = RelocModel;
127 option.LoadAfterCompile = false;
128
129 int status = internalCompile(option);
130 if (status != 0) {
131 ALOGE("LLVM error message: %s\n", getCompilerErrorMessage());
132 return status;
133 }
134
Zonr Chang4f94c522012-04-05 15:09:28 +0800135 OutputFile objFile(objPath);
136 if (objFile.hasError()) {
137 ALOGE("Failed to open %s for write. (%s)", objPath,
138 objFile.getErrorMessage().c_str());
Zonr Changccc39a82012-04-05 10:44:53 +0800139 return 1;
140 }
141
142 if (static_cast<size_t>(objFile.write(getELF(),
143 getELFSize())) != getELFSize()) {
144 objFile.close();
145 ::unlink(objPath);
146 ALOGE("Unable to write ELF to file %s.\n", objPath);
147 return false;
148 }
149
150 mObjectType = ScriptObject::Relocatable;
151
152 return 0;
153}
154
155
156int RSScript::prepareSharedObject(char const *objPath,
157 char const *dsoPath,
158 unsigned long flags) {
159 // TODO: Support cached shared object.
160 return 1;
161}
162
163
164int RSScript::prepareExecutable(char const *cacheDir,
165 char const *cacheName,
166 unsigned long flags) {
167 if (mStatus != ScriptStatus::Unknown) {
168 mErrorCode = BCC_INVALID_OPERATION;
169 ALOGE("Invalid operation: %s\n", __func__);
170 return 1;
171 }
172
173 int status = internalLoadCache(cacheDir, cacheName, /* checkOnly */ false);
174
175 if (status != 0) {
176 CompilerOption option;
177 status = internalCompile(option);
178
179 if (status != 0) {
180 ALOGE("LLVM error message: %s\n", getCompilerErrorMessage());
181 return status;
182 }
183
184 status = writeCache();
185 if (status != 0) {
186 ALOGE("Failed to write the cache for %s\n", cacheName);
187 return status;
188 }
189 }
190
191 // FIXME: Registration can be conditional on the presence of debug metadata
192 registerObjectWithGDB(getELF(), getELFSize()); // thread-safe registration
193
194 mObjectType = ScriptObject::Executable;
195
196 return status;
197}
198
199int RSScript::internalLoadCache(char const *cacheDir, char const *cacheName,
200 bool checkOnly) {
201 if ((cacheDir == NULL) || (cacheName == NULL)) {
202 return 1;
203 }
204
205 // Set cache file Name
206 mCacheName = cacheName;
207
208 // Sanitize mCacheDir. Ensure that mCacheDir ends with '/'.
209 mCacheDir = cacheDir;
210 if (!mCacheDir.empty() && *mCacheDir.rbegin() != '/') {
211 mCacheDir.push_back('/');
212 }
213
214 if (!isCacheable()) {
215 return 1;
216 }
217
218 std::string objPath = getCachedObjectPath();
219 std::string infoPath = getCacheInfoPath();
220
Zonr Chang4f94c522012-04-05 15:09:28 +0800221 // Locks for reading object file and info file.
222 FileMutex<FileBase::kReadLock> objFileMutex(objPath);
223 FileMutex<FileBase::kReadLock> infoFileMutex(infoPath);
224
225 // Aquire read lock for object file.
226 if (objFileMutex.hasError() || !objFileMutex.lock()) {
227 ALOGE("Unable to acquire the lock for %s! (%s)", objPath.c_str(),
228 objFileMutex.getErrorMessage().c_str());
Zonr Changccc39a82012-04-05 10:44:53 +0800229 return 1;
230 }
231
Zonr Chang4f94c522012-04-05 15:09:28 +0800232 // Aquire read lock for info file.
233 if (infoFileMutex.hasError() || !infoFileMutex.lock()) {
234 ALOGE("Unable to acquire the lock for %s! (%s)", infoPath.c_str(),
235 infoFileMutex.getErrorMessage().c_str());
236 return 1;
237 }
238
239 // Open the object file and info file
240 InputFile objFile(objPath);
241 InputFile infoFile(infoPath);
242
243 if (objFile.hasError()) {
244 ALOGE("Unable to open %s for reading! (%s)", objPath.c_str(),
245 objFile.getErrorMessage().c_str());
246 return 1;
247 }
248
249 if (infoFile.hasError()) {
250 ALOGE("Unable to open %s for reading! (%s)", infoPath.c_str(),
251 infoFile.getErrorMessage().c_str());
Zonr Changccc39a82012-04-05 10:44:53 +0800252 return 1;
253 }
254
255 MCCacheReader reader;
256
257 // Register symbol lookup function
258 if (mpExtSymbolLookupFn) {
259 reader.registerSymbolCallback(mpExtSymbolLookupFn,
260 mpExtSymbolLookupFnContext);
261 }
262
263 // Dependencies
Zonr Chang1e2adce2012-04-12 13:29:43 +0800264 reader.addDependency(pathLibBCC_SHA1, sha1LibBCC_SHA1);
265 reader.addDependency(pathLibRS, sha1LibRS);
Zonr Changccc39a82012-04-05 10:44:53 +0800266
267 for (unsigned i = 0; i < mSourceDependencies.size(); i++) {
268 const SourceDependency *source_dep = mSourceDependencies[i];
Zonr Chang1e2adce2012-04-12 13:29:43 +0800269 reader.addDependency(source_dep->getSourceName(),
Zonr Changccc39a82012-04-05 10:44:53 +0800270 source_dep->getSHA1Checksum());
271 }
272
273 if (checkOnly)
Zonr Chang4f94c522012-04-05 15:09:28 +0800274 return !reader.checkCacheFile(objFile, infoFile, this);
Zonr Changccc39a82012-04-05 10:44:53 +0800275
276 // Read cache file
Zonr Chang4f94c522012-04-05 15:09:28 +0800277 ScriptCached *cached = reader.readCacheFile(objFile, infoFile, this);
Zonr Changccc39a82012-04-05 10:44:53 +0800278
279 if (!cached) {
280 mIsContextSlotNotAvail = reader.isContextSlotNotAvail();
281 return 1;
282 }
283
284 mCached = cached;
285 mStatus = ScriptStatus::Cached;
286
287 // Dirty hack for libRS.
288 // TODO(all): This dirty hack should be removed in the future.
289 if (!cached->isLibRSThreadable() && mpExtSymbolLookupFn) {
290 mpExtSymbolLookupFn(mpExtSymbolLookupFnContext, "__clearThreadable");
291 }
292
293 return 0;
294}
295
296int RSScript::internalCompile(const CompilerOption &option) {
297 // Create the ScriptCompiled object
298 mCompiled = new (std::nothrow) ScriptCompiled(this);
299
300 if (!mCompiled) {
301 mErrorCode = BCC_OUT_OF_MEMORY;
302 ALOGE("Out of memory: %s %d\n", __FILE__, __LINE__);
303 return 1;
304 }
305
306 mStatus = ScriptStatus::Compiled;
307
308 // Register symbol lookup function
309 if (mpExtSymbolLookupFn) {
310 mCompiled->registerSymbolCallback(mpExtSymbolLookupFn,
311 mpExtSymbolLookupFnContext);
312 }
313
314 // Set the main source module
315 if (mCompiled->readModule(getSource().getModule()) != 0) {
316 ALOGE("Unable to read source module\n");
317 return 1;
318 }
319
320 // Compile and JIT the code
321 if (mCompiled->compile(option) != 0) {
322 ALOGE("Unable to compile.\n");
323 return 1;
324 }
325
326 return 0;
327}
328
329int RSScript::writeCache() {
330 // Not compiled script or encountered error during the compilation.
331 if ((mStatus != ScriptStatus::Compiled) ||
332 (getCompilerErrorMessage() == NULL))
333 return 1;
334
335 if (isCacheable()) {
Zonr Changccc39a82012-04-05 10:44:53 +0800336 std::string objPath = getCachedObjectPath();
337 std::string infoPath = getCacheInfoPath();
338
Zonr Chang4f94c522012-04-05 15:09:28 +0800339 // Locks for writing object file and info file.
340 FileMutex<FileBase::kWriteLock> objFileMutex(objPath);
341 FileMutex<FileBase::kWriteLock> infoFileMutex(infoPath);
Zonr Changccc39a82012-04-05 10:44:53 +0800342
Zonr Chang4f94c522012-04-05 15:09:28 +0800343 // Acquire write lock for object file.
344 if (objFileMutex.hasError() || !objFileMutex.lock()) {
345 ALOGE("Unable to acquire the lock for %s! (%s)", objPath.c_str(),
346 objFileMutex.getErrorMessage().c_str());
347 return 1;
348 }
Zonr Changccc39a82012-04-05 10:44:53 +0800349
Zonr Chang4f94c522012-04-05 15:09:28 +0800350 // Acquire write lock for info file.
351 if (infoFileMutex.hasError() || !infoFileMutex.lock()) {
352 ALOGE("Unable to acquire the lock for %s! (%s)", infoPath.c_str(),
353 infoFileMutex.getErrorMessage().c_str());
354 return 1;
355 }
Zonr Changccc39a82012-04-05 10:44:53 +0800356
Zonr Chang4f94c522012-04-05 15:09:28 +0800357 // Open the object file and info file
358 OutputFile objFile(objPath);
359 OutputFile infoFile(infoPath);
360
361 if (objFile.hasError()) {
362 ALOGE("Unable to open %s for writing! (%s)", objPath.c_str(),
363 objFile.getErrorMessage().c_str());
364 return 1;
365 }
366
367 if (infoFile.hasError()) {
368 ALOGE("Unable to open %s for writing! (%s)", infoPath.c_str(),
369 infoFile.getErrorMessage().c_str());
370 return 1;
371 }
372
373 MCCacheWriter writer;
Zonr Changccc39a82012-04-05 10:44:53 +0800374
375#ifdef TARGET_BUILD
Zonr Chang4f94c522012-04-05 15:09:28 +0800376 // Dependencies
Zonr Chang1e2adce2012-04-12 13:29:43 +0800377 writer.addDependency(pathLibBCC_SHA1, sha1LibBCC_SHA1);
378 writer.addDependency(pathLibRS, sha1LibRS);
Zonr Changccc39a82012-04-05 10:44:53 +0800379#endif
380
Zonr Chang4f94c522012-04-05 15:09:28 +0800381 for (unsigned i = 0; i < mSourceDependencies.size(); i++) {
382 const SourceDependency *source_dep = mSourceDependencies[i];
Zonr Chang1e2adce2012-04-12 13:29:43 +0800383 writer.addDependency(source_dep->getSourceName(),
Zonr Chang4f94c522012-04-05 15:09:28 +0800384 source_dep->getSHA1Checksum());
385 }
386
387
388 // libRS is threadable dirty hack
389 // TODO: This should be removed in the future
390 uint32_t libRS_threadable = 0;
391 if (mpExtSymbolLookupFn) {
392 libRS_threadable =
393 (uint32_t)mpExtSymbolLookupFn(mpExtSymbolLookupFnContext,
394 "__isThreadable");
395 }
396
397 if (!writer.writeCacheFile(objFile, infoFile, this, libRS_threadable)) {
398 // Erase the file contents.
399 objFile.truncate();
400 infoFile.truncate();
401
402 // Close the file such that we can remove it from the filesystem.
403 objFile.close();
404 infoFile.close();
405
406 if (::unlink(objPath.c_str()) != 0) {
407 ALOGE("Unable to remove the invalid cache file: %s. (reason: %s)\n",
408 objPath.c_str(), ::strerror(errno));
Zonr Changccc39a82012-04-05 10:44:53 +0800409 }
410
Zonr Chang4f94c522012-04-05 15:09:28 +0800411 if (::unlink(infoPath.c_str()) != 0) {
412 ALOGE("Unable to remove the invalid cache file: %s. (reason: %s)\n",
413 infoPath.c_str(), ::strerror(errno));
Zonr Changccc39a82012-04-05 10:44:53 +0800414 }
415 }
Zonr Chang4f94c522012-04-05 15:09:28 +0800416 } // isCacheable()
Zonr Changccc39a82012-04-05 10:44:53 +0800417
418 return 0;
419}
420
Zonr Changccc39a82012-04-05 10:44:53 +0800421char const *RSScript::getCompilerErrorMessage() {
422 if (mStatus != ScriptStatus::Compiled) {
423 mErrorCode = BCC_INVALID_OPERATION;
424 return NULL;
425 }
426
427 return mCompiled->getCompilerErrorMessage();
428}
429
430
431void *RSScript::lookup(const char *name) {
432 switch (mStatus) {
433 case ScriptStatus::Compiled: {
434 return mCompiled->lookup(name);
435 }
436
437 case ScriptStatus::Cached: {
438 return mCached->lookup(name);
439 }
440
441 default: {
442 mErrorCode = BCC_INVALID_OPERATION;
443 return NULL;
444 }
445 }
446}
447
448
449size_t RSScript::getExportVarCount() const {
450 switch (mStatus) {
451 case ScriptStatus::Compiled: {
452 return mCompiled->getExportVarCount();
453 }
454
455 case ScriptStatus::Cached: {
456 return mCached->getExportVarCount();
457 }
458
459 default: {
460 return 0;
461 }
462 }
463}
464
465
466size_t RSScript::getExportFuncCount() const {
467 switch (mStatus) {
468 case ScriptStatus::Compiled: {
469 return mCompiled->getExportFuncCount();
470 }
471
472 case ScriptStatus::Cached: {
473 return mCached->getExportFuncCount();
474 }
475
476 default: {
477 return 0;
478 }
479 }
480}
481
482
483size_t RSScript::getExportForEachCount() const {
484 switch (mStatus) {
485 case ScriptStatus::Compiled: {
486 return mCompiled->getExportForEachCount();
487 }
488
489 case ScriptStatus::Cached: {
490 return mCached->getExportForEachCount();
491 }
492
493 default: {
494 return 0;
495 }
496 }
497}
498
499
500size_t RSScript::getPragmaCount() const {
501 switch (mStatus) {
502 case ScriptStatus::Compiled: {
503 return mCompiled->getPragmaCount();
504 }
505
506 case ScriptStatus::Cached: {
507 return mCached->getPragmaCount();
508 }
509
510 default: {
511 return 0;
512 }
513 }
514}
515
516
517size_t RSScript::getFuncCount() const {
518 switch (mStatus) {
519 case ScriptStatus::Compiled: {
520 return mCompiled->getFuncCount();
521 }
522
523 case ScriptStatus::Cached: {
524 return mCached->getFuncCount();
525 }
526
527 default: {
528 return 0;
529 }
530 }
531}
532
533
534size_t RSScript::getObjectSlotCount() const {
535 switch (mStatus) {
536 case ScriptStatus::Compiled: {
537 return mCompiled->getObjectSlotCount();
538 }
539
540 case ScriptStatus::Cached: {
541 return mCached->getObjectSlotCount();
542 }
543
544 default: {
545 return 0;
546 }
547 }
548}
549
550
551void RSScript::getExportVarList(size_t varListSize, void **varList) {
552 switch (mStatus) {
553#define DELEGATE(STATUS) \
554 case ScriptStatus::STATUS: \
555 m##STATUS->getExportVarList(varListSize, varList); \
556 break;
557
558 DELEGATE(Cached);
559
560 DELEGATE(Compiled);
561#undef DELEGATE
562
563 default: {
564 mErrorCode = BCC_INVALID_OPERATION;
565 }
566 }
567}
568
569void RSScript::getExportVarNameList(std::vector<std::string> &varList) {
570 switch (mStatus) {
571 case ScriptStatus::Compiled: {
572 return mCompiled->getExportVarNameList(varList);
573 }
574
575 default: {
576 mErrorCode = BCC_INVALID_OPERATION;
577 }
578 }
579}
580
581
582void RSScript::getExportFuncList(size_t funcListSize, void **funcList) {
583 switch (mStatus) {
584#define DELEGATE(STATUS) \
585 case ScriptStatus::STATUS: \
586 m##STATUS->getExportFuncList(funcListSize, funcList); \
587 break;
588
589 DELEGATE(Cached);
590
591 DELEGATE(Compiled);
592#undef DELEGATE
593
594 default: {
595 mErrorCode = BCC_INVALID_OPERATION;
596 }
597 }
598}
599
600void RSScript::getExportFuncNameList(std::vector<std::string> &funcList) {
601 switch (mStatus) {
602 case ScriptStatus::Compiled: {
603 return mCompiled->getExportFuncNameList(funcList);
604 }
605
606 default: {
607 mErrorCode = BCC_INVALID_OPERATION;
608 }
609 }
610}
611
612void RSScript::getExportForEachList(size_t funcListSize, void **funcList) {
613 switch (mStatus) {
614#define DELEGATE(STATUS) \
615 case ScriptStatus::STATUS: \
616 m##STATUS->getExportForEachList(funcListSize, funcList); \
617 break;
618
619 DELEGATE(Cached);
620
621 DELEGATE(Compiled);
622#undef DELEGATE
623
624 default: {
625 mErrorCode = BCC_INVALID_OPERATION;
626 }
627 }
628}
629
630void RSScript::getExportForEachNameList(std::vector<std::string> &forEachList) {
631 switch (mStatus) {
632 case ScriptStatus::Compiled: {
633 return mCompiled->getExportForEachNameList(forEachList);
634 }
635
636 default: {
637 mErrorCode = BCC_INVALID_OPERATION;
638 }
639 }
640}
641
642void RSScript::getPragmaList(size_t pragmaListSize,
643 char const **keyList,
644 char const **valueList) {
645 switch (mStatus) {
646#define DELEGATE(STATUS) \
647 case ScriptStatus::STATUS: \
648 m##STATUS->getPragmaList(pragmaListSize, keyList, valueList); \
649 break;
650
651 DELEGATE(Cached);
652
653 DELEGATE(Compiled);
654#undef DELEGATE
655
656 default: {
657 mErrorCode = BCC_INVALID_OPERATION;
658 }
659 }
660}
661
662
663void RSScript::getFuncInfoList(size_t funcInfoListSize,
664 FuncInfo *funcInfoList) {
665 switch (mStatus) {
666#define DELEGATE(STATUS) \
667 case ScriptStatus::STATUS: \
668 m##STATUS->getFuncInfoList(funcInfoListSize, funcInfoList); \
669 break;
670
671 DELEGATE(Cached);
672
673 DELEGATE(Compiled);
674#undef DELEGATE
675
676 default: {
677 mErrorCode = BCC_INVALID_OPERATION;
678 }
679 }
680}
681
682
683void RSScript::getObjectSlotList(size_t objectSlotListSize,
684 uint32_t *objectSlotList) {
685 switch (mStatus) {
686#define DELEGATE(STATUS) \
687 case ScriptStatus::STATUS: \
688 m##STATUS->getObjectSlotList(objectSlotListSize, objectSlotList); \
689 break;
690
691 DELEGATE(Cached);
692
693 DELEGATE(Compiled);
694#undef DELEGATE
695
696 default: {
697 mErrorCode = BCC_INVALID_OPERATION;
698 }
699 }
700}
701
702
703int RSScript::registerSymbolCallback(BCCSymbolLookupFn pFn, void *pContext) {
704 mpExtSymbolLookupFn = pFn;
705 mpExtSymbolLookupFnContext = pContext;
706
707 if (mStatus != ScriptStatus::Unknown) {
708 mErrorCode = BCC_INVALID_OPERATION;
709 ALOGE("Invalid operation: %s\n", __func__);
710 return 1;
711 }
712 return 0;
713}
714
715bool RSScript::isCacheable() const {
716 if (getBooleanProp("debug.bcc.nocache")) {
717 // Android system environment property: Disables the cache mechanism by
718 // setting "debug.bcc.nocache". So we will not load the cache file any
719 // way.
720 return false;
721 }
722
723 if (mCacheDir.empty() || mCacheName.empty()) {
724 // The application developer has not specified the cachePath, so
725 // we don't know where to open the cache file.
726 return false;
727 }
728
729 return true;
730}
731
732size_t RSScript::getELFSize() const {
733 switch (mStatus) {
734 case ScriptStatus::Compiled: {
735 return mCompiled->getELFSize();
736 }
737
738 case ScriptStatus::Cached: {
739 return mCached->getELFSize();
740 }
741
742 default: {
743 return 0;
744 }
745 }
746}
747
748const char *RSScript::getELF() const {
749 switch (mStatus) {
750 case ScriptStatus::Compiled: {
751 return mCompiled->getELF();
752 }
753
754 case ScriptStatus::Cached: {
755 return mCached->getELF();
756 }
757
758 default: {
759 return NULL;
760 }
761 }
762}
763
764} // namespace bcc