• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * copyright 2010, 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 "Config.h"
20 
21 #if USE_OLD_JIT
22 #include "OldJIT/CacheReader.h"
23 #include "OldJIT/CacheWriter.h"
24 #endif
25 
26 #include "MCCacheReader.h"
27 #include "MCCacheWriter.h"
28 
29 #if USE_OLD_JIT
30 #include "OldJIT/ContextManager.h"
31 #endif
32 
33 #include "DebugHelper.h"
34 #include "FileHandle.h"
35 #include "ScriptCompiled.h"
36 #include "ScriptCached.h"
37 #include "Sha1Helper.h"
38 #include "SourceInfo.h"
39 
40 #include <errno.h>
41 #include <sys/stat.h>
42 #include <sys/types.h>
43 
44 #include <new>
45 #include <string.h>
46 #include <cutils/properties.h>
47 
48 
49 namespace {
50 
getBooleanProp(const char * str)51 bool getBooleanProp(const char *str) {
52   char buf[PROPERTY_VALUE_MAX];
53   property_get(str, buf, "0");
54   return strcmp(buf, "0") != 0;
55 }
56 
57 } // namespace anonymous
58 
59 namespace bcc {
60 
~Script()61 Script::~Script() {
62   switch (mStatus) {
63   case ScriptStatus::Compiled:
64     delete mCompiled;
65     break;
66 
67 #if USE_CACHE
68   case ScriptStatus::Cached:
69     delete mCached;
70     break;
71 #endif
72 
73   default:
74     break;
75   }
76 
77   for (size_t i = 0; i < 2; ++i) {
78     delete mSourceList[i];
79   }
80 }
81 
82 
addSourceBC(size_t idx,char const * resName,const char * bitcode,size_t bitcodeSize,unsigned long flags)83 int Script::addSourceBC(size_t idx,
84                         char const *resName,
85                         const char *bitcode,
86                         size_t bitcodeSize,
87                         unsigned long flags) {
88 
89   if (!resName) {
90     mErrorCode = BCC_INVALID_VALUE;
91     LOGE("Invalid argument: resName = NULL\n");
92     return 1;
93   }
94 
95   if (mStatus != ScriptStatus::Unknown) {
96     mErrorCode = BCC_INVALID_OPERATION;
97     LOGE("Bad operation: Adding source after bccPrepareExecutable\n");
98     return 1;
99   }
100 
101   if (!bitcode) {
102     mErrorCode = BCC_INVALID_VALUE;
103     LOGE("Invalid argument: bitcode = NULL\n");
104     return 1;
105   }
106 
107   mSourceList[idx] = SourceInfo::createFromBuffer(resName,
108                                                   bitcode, bitcodeSize,
109                                                   flags);
110 
111   if (!mSourceList[idx]) {
112     mErrorCode = BCC_OUT_OF_MEMORY;
113     LOGE("Out of memory while adding source bitcode\n");
114     return 1;
115   }
116 
117   return 0;
118 }
119 
120 
addSourceModule(size_t idx,llvm::Module * module,unsigned long flags)121 int Script::addSourceModule(size_t idx,
122                             llvm::Module *module,
123                             unsigned long flags) {
124   if (mStatus != ScriptStatus::Unknown) {
125     mErrorCode = BCC_INVALID_OPERATION;
126     LOGE("Bad operation: Adding source after bccPrepareExecutable\n");
127     return 1;
128   }
129 
130   if (!module) {
131     mErrorCode = BCC_INVALID_VALUE;
132     LOGE("Invalid argument: module = NULL\n");
133     return 1;
134   }
135 
136   mSourceList[idx] = SourceInfo::createFromModule(module, flags);
137 
138   if (!mSourceList[idx]) {
139     mErrorCode = BCC_OUT_OF_MEMORY;
140     LOGE("Out of memory when add source module\n");
141     return 1;
142   }
143 
144   return 0;
145 }
146 
147 
addSourceFile(size_t idx,char const * path,unsigned long flags)148 int Script::addSourceFile(size_t idx,
149                           char const *path,
150                           unsigned long flags) {
151   if (mStatus != ScriptStatus::Unknown) {
152     mErrorCode = BCC_INVALID_OPERATION;
153     LOGE("Bad operation: Adding source after bccPrepareExecutable\n");
154     return 1;
155   }
156 
157   if (!path) {
158     mErrorCode = BCC_INVALID_VALUE;
159     LOGE("Invalid argument: path = NULL\n");
160     return 1;
161   }
162 
163   struct stat sb;
164   if (stat(path, &sb) != 0) {
165     mErrorCode = BCC_INVALID_VALUE;
166     LOGE("File not found: %s\n", path);
167     return 1;
168   }
169 
170   mSourceList[idx] = SourceInfo::createFromFile(path, flags);
171 
172   if (!mSourceList[idx]) {
173     mErrorCode = BCC_OUT_OF_MEMORY;
174     LOGE("Out of memory while adding source file\n");
175     return 1;
176   }
177 
178   return 0;
179 }
180 
prepareSharedObject(char const * cacheDir,char const * cacheName,unsigned long flags)181 int Script::prepareSharedObject(char const *cacheDir,
182                                 char const *cacheName,
183                                 unsigned long flags) {
184 #if USE_CACHE
185   if (cacheDir && cacheName) {
186     // Set Cache Directory and File Name
187     mCacheDir = cacheDir;
188     mCacheName = cacheName;
189 
190     if (!mCacheDir.empty() && *mCacheDir.rbegin() != '/') {
191       mCacheDir.push_back('/'); // Ensure mCacheDir is end with '/'
192     }
193 
194     // Check Cache File
195     if (internalLoadCache(true) == 0) {
196       return 0;
197     }
198   }
199 #endif
200   int status = internalCompile(true);
201   if (status != 0) {
202     LOGE("LLVM error message: %s\n", getCompilerErrorMessage());
203   }
204   return status;
205 }
206 
207 
prepareExecutable(char const * cacheDir,char const * cacheName,unsigned long flags)208 int Script::prepareExecutable(char const *cacheDir,
209                               char const *cacheName,
210                               unsigned long flags) {
211   if (mStatus != ScriptStatus::Unknown) {
212     mErrorCode = BCC_INVALID_OPERATION;
213     LOGE("Invalid operation: %s\n", __func__);
214     return 1;
215   }
216 
217 #if USE_CACHE
218   if (cacheDir && cacheName) {
219     // Set Cache Directory and File Name
220     mCacheDir = cacheDir;
221     mCacheName = cacheName;
222 
223     if (!mCacheDir.empty() && *mCacheDir.rbegin() != '/') {
224       mCacheDir.push_back('/'); // Ensure mCacheDir is end with '/'
225     }
226 
227     // Load Cache File
228     if (internalLoadCache(false) == 0) {
229       return 0;
230     }
231   }
232 #endif
233 
234   int status = internalCompile(false);
235   if (status != 0) {
236     LOGE("LLVM error message: %s\n", getCompilerErrorMessage());
237   }
238   return status;
239 }
240 
241 
242 #if USE_CACHE
internalLoadCache(bool checkOnly)243 int Script::internalLoadCache(bool checkOnly) {
244   if (getBooleanProp("debug.bcc.nocache")) {
245     // Android system environment property disable the cache mechanism by
246     // setting "debug.bcc.nocache".  So we will not load the cache file any
247     // way.
248     return 1;
249   }
250 
251   if (mCacheDir.empty() || mCacheName.empty()) {
252     // The application developer has not specify the cachePath, so
253     // we don't know where to open the cache file.
254     return 1;
255   }
256 
257 #if USE_OLD_JIT
258   std::string objPath(mCacheDir + mCacheName + ".jit-image");
259   std::string infoPath(mCacheDir + mCacheName + ".oBCC"); // TODO: .info instead
260 #elif USE_MCJIT
261   std::string objPath(mCacheDir + mCacheName + ".o");
262   std::string infoPath(mCacheDir + mCacheName + ".info");
263 #endif
264 
265   FileHandle objFile;
266   if (objFile.open(objPath.c_str(), OpenMode::Read) < 0) {
267     // Unable to open the executable file in read mode.
268     return 1;
269   }
270 
271   FileHandle infoFile;
272   if (infoFile.open(infoPath.c_str(), OpenMode::Read) < 0) {
273     // Unable to open the metadata information file in read mode.
274     return 1;
275   }
276 
277 #if USE_OLD_JIT
278   CacheReader reader;
279 #elif USE_MCJIT
280   MCCacheReader reader;
281 
282   // Register symbol lookup function
283   if (mpExtSymbolLookupFn) {
284     reader.registerSymbolCallback(mpExtSymbolLookupFn,
285                                       mpExtSymbolLookupFnContext);
286   }
287 #endif
288 
289   // Dependencies
290   reader.addDependency(BCC_FILE_RESOURCE, pathLibBCC_SHA1, sha1LibBCC_SHA1);
291   reader.addDependency(BCC_FILE_RESOURCE, pathLibRS, sha1LibRS);
292 
293   for (size_t i = 0; i < 2; ++i) {
294     if (mSourceList[i]) {
295       mSourceList[i]->introDependency(reader);
296     }
297   }
298 
299   if (checkOnly)
300     return !reader.checkCacheFile(&objFile, &infoFile, this);
301 
302   // Read cache file
303   ScriptCached *cached = reader.readCacheFile(&objFile, &infoFile, this);
304 
305   if (!cached) {
306     mIsContextSlotNotAvail = reader.isContextSlotNotAvail();
307     return 1;
308   }
309 
310   mCached = cached;
311   mStatus = ScriptStatus::Cached;
312 
313   // Dirty hack for libRS.
314   // TODO(all):  This dirty hack should be removed in the future.
315   if (!cached->isLibRSThreadable() && mpExtSymbolLookupFn) {
316     mpExtSymbolLookupFn(mpExtSymbolLookupFnContext, "__clearThreadable");
317   }
318 
319   return 0;
320 }
321 #endif
322 
internalCompile(bool compileOnly)323 int Script::internalCompile(bool compileOnly) {
324   // Create the ScriptCompiled object
325   mCompiled = new (std::nothrow) ScriptCompiled(this);
326 
327   if (!mCompiled) {
328     mErrorCode = BCC_OUT_OF_MEMORY;
329     LOGE("Out of memory: %s %d\n", __FILE__, __LINE__);
330     return 1;
331   }
332 
333   mStatus = ScriptStatus::Compiled;
334 
335   // Register symbol lookup function
336   if (mpExtSymbolLookupFn) {
337     mCompiled->registerSymbolCallback(mpExtSymbolLookupFn,
338                                       mpExtSymbolLookupFnContext);
339   }
340 
341   // Parse Bitcode File (if necessary)
342   for (size_t i = 0; i < 2; ++i) {
343     if (mSourceList[i] && mSourceList[i]->prepareModule(mCompiled) != 0) {
344       LOGE("Unable to parse bitcode for source[%lu]\n", (unsigned long)i);
345       return 1;
346     }
347   }
348 
349   // Set the main source module
350   if (!mSourceList[0] || !mSourceList[0]->getModule()) {
351     LOGE("Source bitcode is not setted.\n");
352     return 1;
353   }
354 
355   if (mCompiled->readModule(mSourceList[0]->takeModule()) != 0) {
356     LOGE("Unable to read source module\n");
357     return 1;
358   }
359 
360   // Link the source module with the library module
361   if (mSourceList[1]) {
362     if (mCompiled->linkModule(mSourceList[1]->takeModule()) != 0) {
363       LOGE("Unable to link library module\n");
364       return 1;
365     }
366   }
367 
368   // Compile and JIT the code
369   if (mCompiled->compile(compileOnly) != 0) {
370     LOGE("Unable to compile.\n");
371     return 1;
372   }
373 
374 #if USE_CACHE
375   // Note: If we re-compile the script because the cached context slot not
376   // available, then we don't have to write the cache.
377 
378   // Note: If the address of the context is not in the context slot, then
379   // we don't have to cache it.
380 
381   if (!mCacheDir.empty() &&
382       !mCacheName.empty() &&
383 #if USE_OLD_JIT
384       !mIsContextSlotNotAvail &&
385       ContextManager::get().isManagingContext(getContext()) &&
386 #endif
387       !getBooleanProp("debug.bcc.nocache")) {
388 
389 #if USE_OLD_JIT
390     std::string objPath(mCacheDir + mCacheName + ".jit-image");
391     std::string infoPath(mCacheDir + mCacheName + ".oBCC");
392 #elif USE_MCJIT
393     std::string objPath(mCacheDir + mCacheName + ".o");
394     std::string infoPath(mCacheDir + mCacheName + ".info");
395 #endif
396 
397 
398     // Remove the file if it already exists before writing the new file.
399     // The old file may still be mapped elsewhere in memory and we do not want
400     // to modify its contents.  (The same script may be running concurrently in
401     // the same process or a different process!)
402     ::unlink(objPath.c_str());
403 #if !USE_OLD_JIT && USE_MCJIT
404     ::unlink(infoPath.c_str());
405 #endif
406 
407     FileHandle objFile;
408     FileHandle infoFile;
409 
410     if (objFile.open(objPath.c_str(), OpenMode::Write) >= 0 &&
411         infoFile.open(infoPath.c_str(), OpenMode::Write) >= 0) {
412 
413 #if USE_OLD_JIT
414       CacheWriter writer;
415 #elif USE_MCJIT
416       MCCacheWriter writer;
417 #endif
418 
419 #ifdef TARGET_BUILD
420       // Dependencies
421       writer.addDependency(BCC_FILE_RESOURCE, pathLibBCC_SHA1, sha1LibBCC_SHA1);
422       writer.addDependency(BCC_FILE_RESOURCE, pathLibRS, sha1LibRS);
423 #endif
424 
425       for (size_t i = 0; i < 2; ++i) {
426         if (mSourceList[i]) {
427           mSourceList[i]->introDependency(writer);
428         }
429       }
430 
431       // libRS is threadable dirty hack
432       // TODO: This should be removed in the future
433       uint32_t libRS_threadable = 0;
434       if (mpExtSymbolLookupFn) {
435         libRS_threadable =
436           (uint32_t)mpExtSymbolLookupFn(mpExtSymbolLookupFnContext,
437                                         "__isThreadable");
438       }
439 
440       if (!writer.writeCacheFile(&objFile, &infoFile, this, libRS_threadable)) {
441         objFile.truncate();
442         objFile.close();
443 
444         if (unlink(objPath.c_str()) != 0) {
445           LOGE("Unable to remove the invalid cache file: %s. (reason: %s)\n",
446                objPath.c_str(), strerror(errno));
447         }
448 
449         infoFile.truncate();
450         infoFile.close();
451 
452         if (unlink(infoPath.c_str()) != 0) {
453           LOGE("Unable to remove the invalid cache file: %s. (reason: %s)\n",
454                infoPath.c_str(), strerror(errno));
455         }
456       }
457     }
458   }
459 #endif // USE_CACHE
460 
461   return 0;
462 }
463 
464 
getCompilerErrorMessage()465 char const *Script::getCompilerErrorMessage() {
466   if (mStatus != ScriptStatus::Compiled) {
467     mErrorCode = BCC_INVALID_OPERATION;
468     return NULL;
469   }
470 
471   return mCompiled->getCompilerErrorMessage();
472 }
473 
474 
lookup(const char * name)475 void *Script::lookup(const char *name) {
476   switch (mStatus) {
477     case ScriptStatus::Compiled: {
478       return mCompiled->lookup(name);
479     }
480 
481 #if USE_CACHE
482     case ScriptStatus::Cached: {
483       return mCached->lookup(name);
484     }
485 #endif
486 
487     default: {
488       mErrorCode = BCC_INVALID_OPERATION;
489       return NULL;
490     }
491   }
492 }
493 
494 
getExportVarCount() const495 size_t Script::getExportVarCount() const {
496   switch (mStatus) {
497     case ScriptStatus::Compiled: {
498       return mCompiled->getExportVarCount();
499     }
500 
501 #if USE_CACHE
502     case ScriptStatus::Cached: {
503       return mCached->getExportVarCount();
504     }
505 #endif
506 
507     default: {
508       return 0;
509     }
510   }
511 }
512 
513 
getExportFuncCount() const514 size_t Script::getExportFuncCount() const {
515   switch (mStatus) {
516     case ScriptStatus::Compiled: {
517       return mCompiled->getExportFuncCount();
518     }
519 
520 #if USE_CACHE
521     case ScriptStatus::Cached: {
522       return mCached->getExportFuncCount();
523     }
524 #endif
525 
526     default: {
527       return 0;
528     }
529   }
530 }
531 
532 
getPragmaCount() const533 size_t Script::getPragmaCount() const {
534   switch (mStatus) {
535     case ScriptStatus::Compiled: {
536       return mCompiled->getPragmaCount();
537     }
538 
539 #if USE_CACHE
540     case ScriptStatus::Cached: {
541       return mCached->getPragmaCount();
542     }
543 #endif
544 
545     default: {
546       return 0;
547     }
548   }
549 }
550 
551 
getFuncCount() const552 size_t Script::getFuncCount() const {
553   switch (mStatus) {
554     case ScriptStatus::Compiled: {
555       return mCompiled->getFuncCount();
556     }
557 
558 #if USE_CACHE
559     case ScriptStatus::Cached: {
560       return mCached->getFuncCount();
561     }
562 #endif
563 
564     default: {
565       return 0;
566     }
567   }
568 }
569 
570 
getObjectSlotCount() const571 size_t Script::getObjectSlotCount() const {
572   switch (mStatus) {
573     case ScriptStatus::Compiled: {
574       return mCompiled->getObjectSlotCount();
575     }
576 
577 #if USE_CACHE
578     case ScriptStatus::Cached: {
579       return mCached->getObjectSlotCount();
580     }
581 #endif
582 
583     default: {
584       return 0;
585     }
586   }
587 }
588 
589 
getExportVarList(size_t varListSize,void ** varList)590 void Script::getExportVarList(size_t varListSize, void **varList) {
591   switch (mStatus) {
592 #define DELEGATE(STATUS) \
593     case ScriptStatus::STATUS:                           \
594       m##STATUS->getExportVarList(varListSize, varList); \
595       break;
596 
597 #if USE_CACHE
598     DELEGATE(Cached);
599 #endif
600 
601     DELEGATE(Compiled);
602 #undef DELEGATE
603 
604     default: {
605       mErrorCode = BCC_INVALID_OPERATION;
606     }
607   }
608 }
609 
getExportVarNameList(std::vector<std::string> & varList)610 void Script::getExportVarNameList(std::vector<std::string> &varList) {
611   switch (mStatus) {
612     case ScriptStatus::Compiled: {
613       return mCompiled->getExportVarNameList(varList);
614     }
615 
616     default: {
617       mErrorCode = BCC_INVALID_OPERATION;
618     }
619   }
620 }
621 
622 
getExportFuncList(size_t funcListSize,void ** funcList)623 void Script::getExportFuncList(size_t funcListSize, void **funcList) {
624   switch (mStatus) {
625 #define DELEGATE(STATUS) \
626     case ScriptStatus::STATUS:                              \
627       m##STATUS->getExportFuncList(funcListSize, funcList); \
628       break;
629 
630 #if USE_CACHE
631     DELEGATE(Cached);
632 #endif
633 
634     DELEGATE(Compiled);
635 #undef DELEGATE
636 
637     default: {
638       mErrorCode = BCC_INVALID_OPERATION;
639     }
640   }
641 }
642 
getExportFuncNameList(std::vector<std::string> & funcList)643 void Script::getExportFuncNameList(std::vector<std::string> &funcList) {
644   switch (mStatus) {
645     case ScriptStatus::Compiled: {
646       return mCompiled->getExportFuncNameList(funcList);
647     }
648 
649     default: {
650       mErrorCode = BCC_INVALID_OPERATION;
651     }
652   }
653 }
654 
655 
getPragmaList(size_t pragmaListSize,char const ** keyList,char const ** valueList)656 void Script::getPragmaList(size_t pragmaListSize,
657                            char const **keyList,
658                            char const **valueList) {
659   switch (mStatus) {
660 #define DELEGATE(STATUS) \
661     case ScriptStatus::STATUS:                                      \
662       m##STATUS->getPragmaList(pragmaListSize, keyList, valueList); \
663       break;
664 
665 #if USE_CACHE
666     DELEGATE(Cached);
667 #endif
668 
669     DELEGATE(Compiled);
670 #undef DELEGATE
671 
672     default: {
673       mErrorCode = BCC_INVALID_OPERATION;
674     }
675   }
676 }
677 
678 
getFuncInfoList(size_t funcInfoListSize,FuncInfo * funcInfoList)679 void Script::getFuncInfoList(size_t funcInfoListSize,
680                              FuncInfo *funcInfoList) {
681   switch (mStatus) {
682 #define DELEGATE(STATUS) \
683     case ScriptStatus::STATUS:                                    \
684       m##STATUS->getFuncInfoList(funcInfoListSize, funcInfoList); \
685       break;
686 
687 #if USE_CACHE
688     DELEGATE(Cached);
689 #endif
690 
691     DELEGATE(Compiled);
692 #undef DELEGATE
693 
694     default: {
695       mErrorCode = BCC_INVALID_OPERATION;
696     }
697   }
698 }
699 
700 
getObjectSlotList(size_t objectSlotListSize,uint32_t * objectSlotList)701 void Script::getObjectSlotList(size_t objectSlotListSize,
702                                uint32_t *objectSlotList) {
703   switch (mStatus) {
704 #define DELEGATE(STATUS)     \
705     case ScriptStatus::STATUS:                                          \
706       m##STATUS->getObjectSlotList(objectSlotListSize, objectSlotList); \
707       break;
708 
709 #if USE_CACHE
710     DELEGATE(Cached);
711 #endif
712 
713     DELEGATE(Compiled);
714 #undef DELEGATE
715 
716     default: {
717       mErrorCode = BCC_INVALID_OPERATION;
718     }
719   }
720 }
721 
722 
723 #if USE_OLD_JIT
getContext()724 char *Script::getContext() {
725   switch (mStatus) {
726 
727 #if USE_CACHE
728     case ScriptStatus::Cached: {
729       return mCached->getContext();
730     }
731 #endif
732 
733     case ScriptStatus::Compiled: {
734       return mCompiled->getContext();
735     }
736 
737     default: {
738       mErrorCode = BCC_INVALID_OPERATION;
739       return NULL;
740     }
741   }
742 }
743 #endif
744 
745 
registerSymbolCallback(BCCSymbolLookupFn pFn,void * pContext)746 int Script::registerSymbolCallback(BCCSymbolLookupFn pFn, void *pContext) {
747   mpExtSymbolLookupFn = pFn;
748   mpExtSymbolLookupFnContext = pContext;
749 
750   if (mStatus != ScriptStatus::Unknown) {
751     mErrorCode = BCC_INVALID_OPERATION;
752     LOGE("Invalid operation: %s\n", __func__);
753     return 1;
754   }
755   return 0;
756 }
757 
758 #if USE_MCJIT
getELFSize() const759 size_t Script::getELFSize() const {
760   switch (mStatus) {
761     case ScriptStatus::Compiled: {
762       return mCompiled->getELFSize();
763     }
764 
765     default: {
766       return 0;
767     }
768   }
769 }
770 
getELF() const771 const char *Script::getELF() const {
772   switch (mStatus) {
773     case ScriptStatus::Compiled: {
774       return mCompiled->getELF();
775     }
776 
777     default: {
778       return NULL;
779     }
780   }
781 }
782 #endif
783 
784 } // namespace bcc
785