blob: 2ca97a5f48168cce2fdfb0fb27c4b4d4171c8170 [file] [log] [blame]
Zonr Chang19218c02012-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
Stephen Hines4a68b1c2012-05-03 12:28:14 -070017#include "Script.h"
Zonr Chang19218c02012-04-05 10:44:53 +080018
Stephen Hines4a68b1c2012-05-03 12:28:14 -070019#include <errno.h>
20#include <sys/stat.h>
21#include <sys/types.h>
22#include <unistd.h>
23
24#include <new>
Stephen Hines7dfc4d82012-05-03 12:25:21 -070025#include <cstring>
26
27#include <llvm/ADT/STLExtras.h>
28
Stephen Hines4a68b1c2012-05-03 12:28:14 -070029#include <cutils/properties.h>
Zonr Chang19218c02012-04-05 10:44:53 +080030
Stephen Hines4a68b1c2012-05-03 12:28:14 -070031#include "Config.h"
32
33#include "MCCacheReader.h"
34#include "MCCacheWriter.h"
35#include "CompilerOption.h"
36
37#include "DebugHelper.h"
38#include "FileMutex.h"
39#include "GDBJITRegistrar.h"
40#include "InputFile.h"
41#include "OutputFile.h"
42#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 {
Zonr Chang19218c02012-04-05 10:44:53 +080058
Stephen Hines7dfc4d82012-05-03 12:25:21 -070059RSScript::SourceDependency::SourceDependency(const std::string &pSourceName,
60 const uint8_t *pSHA1)
61 : mSourceName(pSourceName) {
62 ::memcpy(mSHA1, pSHA1, sizeof(mSHA1));
63 return;
64}
65
Zonr Chang19218c02012-04-05 10:44:53 +080066RSScript::RSScript(Source &pSource)
Stephen Hines4a68b1c2012-05-03 12:28:14 -070067 : Script(pSource),
68 mpExtSymbolLookupFn(NULL),
69 mpExtSymbolLookupFnContext(NULL) {
70 resetState();
71 return;
72}
Zonr Chang19218c02012-04-05 10:44:53 +080073
Stephen Hines7dfc4d82012-05-03 12:25:21 -070074RSScript::~RSScript() {
Stephen Hines4a68b1c2012-05-03 12:28:14 -070075 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 }
Stephen Hines7dfc4d82012-05-03 12:25:21 -070087 llvm::DeleteContainerPointers(mSourceDependencies);
88}
89
Stephen Hines4a68b1c2012-05-03 12:28:14 -070090void 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;
Stephen Hines7dfc4d82012-05-03 12:25:21 -070099 llvm::DeleteContainerPointers(mSourceDependencies);
Stephen Hines4a68b1c2012-05-03 12:28:14 -0700100 return;
101}
102
103bool RSScript::doReset() {
104 resetState();
Stephen Hines7dfc4d82012-05-03 12:25:21 -0700105 return true;
106}
107
108bool RSScript::addSourceDependency(const std::string &pSourceName,
109 const uint8_t *pSHA1) {
110 SourceDependency *source_dep =
111 new (std::nothrow) SourceDependency(pSourceName, pSHA1);
112 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);
Zonr Chang19218c02012-04-05 10:44:53 +0800119 return true;
120}
Stephen Hines4a68b1c2012-05-03 12:28:14 -0700121
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
135 OutputFile objFile(objPath);
136 if (objFile.hasError()) {
137 ALOGE("Failed to open %s for write. (%s)", objPath,
138 objFile.getErrorMessage().c_str());
139 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 // Santize 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
221 // 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());
229 return 1;
230 }
231
232 // 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());
252 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
264 reader.addDependency(pathLibBCC_SHA1, sha1LibBCC_SHA1);
265 reader.addDependency(pathLibRS, sha1LibRS);
266
267 for (unsigned i = 0; i < mSourceDependencies.size(); i++) {
268 const SourceDependency *source_dep = mSourceDependencies[i];
269 reader.addDependency(source_dep->getSourceName(),
270 source_dep->getSHA1Checksum());
271 }
272
273 if (checkOnly)
274 return !reader.checkCacheFile(objFile, infoFile, this);
275
276 // Read cache file
277 ScriptCached *cached = reader.readCacheFile(objFile, infoFile, this);
278
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 // Note: If we re-compile the script because the cached context slot not
336 // available, then we don't have to write the cache.
337
338 // Note: If the address of the context is not in the context slot, then
339 // we don't have to cache it.
340
341 if (isCacheable()) {
342 std::string objPath = getCachedObjectPath();
343 std::string infoPath = getCacheInfoPath();
344
345 // Locks for writing object file and info file.
346 FileMutex<FileBase::kWriteLock> objFileMutex(objPath);
347 FileMutex<FileBase::kWriteLock> infoFileMutex(infoPath);
348
349 // Aquire write lock for object file.
350 if (objFileMutex.hasError() || !objFileMutex.lock()) {
351 ALOGE("Unable to acquire the lock for %s! (%s)", objPath.c_str(),
352 objFileMutex.getErrorMessage().c_str());
353 return 1;
354 }
355
356 // Aquire write lock for info file.
357 if (infoFileMutex.hasError() || !infoFileMutex.lock()) {
358 ALOGE("Unable to acquire the lock for %s! (%s)", infoPath.c_str(),
359 infoFileMutex.getErrorMessage().c_str());
360 return 1;
361 }
362
363 // Open the object file and info file
364 OutputFile objFile(objPath);
365 OutputFile infoFile(infoPath);
366
367 if (objFile.hasError()) {
368 ALOGE("Unable to open %s for writing! (%s)", objPath.c_str(),
369 objFile.getErrorMessage().c_str());
370 return 1;
371 }
372
373 if (infoFile.hasError()) {
374 ALOGE("Unable to open %s for writing! (%s)", infoPath.c_str(),
375 infoFile.getErrorMessage().c_str());
376 return 1;
377 }
378
379 MCCacheWriter writer;
380
381#ifdef TARGET_BUILD
382 // Dependencies
383 writer.addDependency(pathLibBCC_SHA1, sha1LibBCC_SHA1);
384 writer.addDependency(pathLibRS, sha1LibRS);
385#endif
386
387 for (unsigned i = 0; i < mSourceDependencies.size(); i++) {
388 const SourceDependency *source_dep = mSourceDependencies[i];
389 writer.addDependency(source_dep->getSourceName(),
390 source_dep->getSHA1Checksum());
391 }
392
393
394 // libRS is threadable dirty hack
395 // TODO: This should be removed in the future
396 uint32_t libRS_threadable = 0;
397 if (mpExtSymbolLookupFn) {
398 libRS_threadable =
399 (uint32_t)mpExtSymbolLookupFn(mpExtSymbolLookupFnContext,
400 "__isThreadable");
401 }
402
403 if (!writer.writeCacheFile(objFile, infoFile, this, libRS_threadable)) {
404 // Erase the file contents.
405 objFile.truncate();
406 infoFile.truncate();
407
408 // Close the file such that we can removed it from the filesystem.
409 objFile.close();
410 infoFile.close();
411
412 if (::unlink(objPath.c_str()) != 0) {
413 ALOGE("Unable to remove the invalid cache file: %s. (reason: %s)\n",
414 objPath.c_str(), ::strerror(errno));
415 }
416
417 if (::unlink(infoPath.c_str()) != 0) {
418 ALOGE("Unable to remove the invalid cache file: %s. (reason: %s)\n",
419 infoPath.c_str(), ::strerror(errno));
420 }
421 }
422 } // isCacheable()
423
424 return 0;
425}
426
427char const *RSScript::getCompilerErrorMessage() {
428 if (mStatus != ScriptStatus::Compiled) {
429 mErrorCode = BCC_INVALID_OPERATION;
430 return NULL;
431 }
432
433 return mCompiled->getCompilerErrorMessage();
434}
435
436
437void *RSScript::lookup(const char *name) {
438 switch (mStatus) {
439 case ScriptStatus::Compiled: {
440 return mCompiled->lookup(name);
441 }
442
443 case ScriptStatus::Cached: {
444 return mCached->lookup(name);
445 }
446
447 default: {
448 mErrorCode = BCC_INVALID_OPERATION;
449 return NULL;
450 }
451 }
452}
453
454
455size_t RSScript::getExportVarCount() const {
456 switch (mStatus) {
457 case ScriptStatus::Compiled: {
458 return mCompiled->getExportVarCount();
459 }
460
461 case ScriptStatus::Cached: {
462 return mCached->getExportVarCount();
463 }
464
465 default: {
466 return 0;
467 }
468 }
469}
470
471
472size_t RSScript::getExportFuncCount() const {
473 switch (mStatus) {
474 case ScriptStatus::Compiled: {
475 return mCompiled->getExportFuncCount();
476 }
477
478 case ScriptStatus::Cached: {
479 return mCached->getExportFuncCount();
480 }
481
482 default: {
483 return 0;
484 }
485 }
486}
487
488
489size_t RSScript::getExportForEachCount() const {
490 switch (mStatus) {
491 case ScriptStatus::Compiled: {
492 return mCompiled->getExportForEachCount();
493 }
494
495 case ScriptStatus::Cached: {
496 return mCached->getExportForEachCount();
497 }
498
499 default: {
500 return 0;
501 }
502 }
503}
504
505
506size_t RSScript::getPragmaCount() const {
507 switch (mStatus) {
508 case ScriptStatus::Compiled: {
509 return mCompiled->getPragmaCount();
510 }
511
512 case ScriptStatus::Cached: {
513 return mCached->getPragmaCount();
514 }
515
516 default: {
517 return 0;
518 }
519 }
520}
521
522
523size_t RSScript::getFuncCount() const {
524 switch (mStatus) {
525 case ScriptStatus::Compiled: {
526 return mCompiled->getFuncCount();
527 }
528
529 case ScriptStatus::Cached: {
530 return mCached->getFuncCount();
531 }
532
533 default: {
534 return 0;
535 }
536 }
537}
538
539
540size_t RSScript::getObjectSlotCount() const {
541 switch (mStatus) {
542 case ScriptStatus::Compiled: {
543 return mCompiled->getObjectSlotCount();
544 }
545
546 case ScriptStatus::Cached: {
547 return mCached->getObjectSlotCount();
548 }
549
550 default: {
551 return 0;
552 }
553 }
554}
555
556
557void RSScript::getExportVarList(size_t varListSize, void **varList) {
558 switch (mStatus) {
559#define DELEGATE(STATUS) \
560 case ScriptStatus::STATUS: \
561 m##STATUS->getExportVarList(varListSize, varList); \
562 break;
563
564 DELEGATE(Cached);
565
566 DELEGATE(Compiled);
567#undef DELEGATE
568
569 default: {
570 mErrorCode = BCC_INVALID_OPERATION;
571 }
572 }
573}
574
575void RSScript::getExportVarNameList(std::vector<std::string> &varList) {
576 switch (mStatus) {
577 case ScriptStatus::Compiled: {
578 return mCompiled->getExportVarNameList(varList);
579 }
580
581 default: {
582 mErrorCode = BCC_INVALID_OPERATION;
583 }
584 }
585}
586
587
588void RSScript::getExportFuncList(size_t funcListSize, void **funcList) {
589 switch (mStatus) {
590#define DELEGATE(STATUS) \
591 case ScriptStatus::STATUS: \
592 m##STATUS->getExportFuncList(funcListSize, funcList); \
593 break;
594
595 DELEGATE(Cached);
596
597 DELEGATE(Compiled);
598#undef DELEGATE
599
600 default: {
601 mErrorCode = BCC_INVALID_OPERATION;
602 }
603 }
604}
605
606void RSScript::getExportFuncNameList(std::vector<std::string> &funcList) {
607 switch (mStatus) {
608 case ScriptStatus::Compiled: {
609 return mCompiled->getExportFuncNameList(funcList);
610 }
611
612 default: {
613 mErrorCode = BCC_INVALID_OPERATION;
614 }
615 }
616}
617
618void RSScript::getExportForEachList(size_t funcListSize, void **funcList) {
619 switch (mStatus) {
620#define DELEGATE(STATUS) \
621 case ScriptStatus::STATUS: \
622 m##STATUS->getExportForEachList(funcListSize, funcList); \
623 break;
624
625 DELEGATE(Cached);
626
627 DELEGATE(Compiled);
628#undef DELEGATE
629
630 default: {
631 mErrorCode = BCC_INVALID_OPERATION;
632 }
633 }
634}
635
636void RSScript::getExportForEachNameList(std::vector<std::string> &forEachList) {
637 switch (mStatus) {
638 case ScriptStatus::Compiled: {
639 return mCompiled->getExportForEachNameList(forEachList);
640 }
641
642 default: {
643 mErrorCode = BCC_INVALID_OPERATION;
644 }
645 }
646}
647
648void RSScript::getPragmaList(size_t pragmaListSize,
649 char const **keyList,
650 char const **valueList) {
651 switch (mStatus) {
652#define DELEGATE(STATUS) \
653 case ScriptStatus::STATUS: \
654 m##STATUS->getPragmaList(pragmaListSize, keyList, valueList); \
655 break;
656
657 DELEGATE(Cached);
658
659 DELEGATE(Compiled);
660#undef DELEGATE
661
662 default: {
663 mErrorCode = BCC_INVALID_OPERATION;
664 }
665 }
666}
667
668
669void RSScript::getFuncInfoList(size_t funcInfoListSize,
670 FuncInfo *funcInfoList) {
671 switch (mStatus) {
672#define DELEGATE(STATUS) \
673 case ScriptStatus::STATUS: \
674 m##STATUS->getFuncInfoList(funcInfoListSize, funcInfoList); \
675 break;
676
677 DELEGATE(Cached);
678
679 DELEGATE(Compiled);
680#undef DELEGATE
681
682 default: {
683 mErrorCode = BCC_INVALID_OPERATION;
684 }
685 }
686}
687
688
689void RSScript::getObjectSlotList(size_t objectSlotListSize,
690 uint32_t *objectSlotList) {
691 switch (mStatus) {
692#define DELEGATE(STATUS) \
693 case ScriptStatus::STATUS: \
694 m##STATUS->getObjectSlotList(objectSlotListSize, objectSlotList); \
695 break;
696
697 DELEGATE(Cached);
698
699 DELEGATE(Compiled);
700#undef DELEGATE
701
702 default: {
703 mErrorCode = BCC_INVALID_OPERATION;
704 }
705 }
706}
707
708
709int RSScript::registerSymbolCallback(BCCSymbolLookupFn pFn, void *pContext) {
710 mpExtSymbolLookupFn = pFn;
711 mpExtSymbolLookupFnContext = pContext;
712
713 if (mStatus != ScriptStatus::Unknown) {
714 mErrorCode = BCC_INVALID_OPERATION;
715 ALOGE("Invalid operation: %s\n", __func__);
716 return 1;
717 }
718 return 0;
719}
720
721bool RSScript::isCacheable() const {
722 if (getBooleanProp("debug.bcc.nocache")) {
723 // Android system environment property: Disables the cache mechanism by
724 // setting "debug.bcc.nocache". So we will not load the cache file any
725 // way.
726 return false;
727 }
728
729 if (mCacheDir.empty() || mCacheName.empty()) {
730 // The application developer has not specified the cachePath, so
731 // we don't know where to open the cache file.
732 return false;
733 }
734
735 return true;
736}
737
738size_t RSScript::getELFSize() const {
739 switch (mStatus) {
740 case ScriptStatus::Compiled: {
741 return mCompiled->getELFSize();
742 }
743
744 case ScriptStatus::Cached: {
745 return mCached->getELFSize();
746 }
747
748 default: {
749 return 0;
750 }
751 }
752}
753
754const char *RSScript::getELF() const {
755 switch (mStatus) {
756 case ScriptStatus::Compiled: {
757 return mCompiled->getELF();
758 }
759
760 case ScriptStatus::Cached: {
761 return mCached->getELF();
762 }
763
764 default: {
765 return NULL;
766 }
767 }
768}
769
770} // namespace bcc