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