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