blob: af37ab61fe15b1143d00d9893925eebf0c222b42 [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
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"
38#include "FileHandle.h"
39#include "GDBJITRegistrar.h"
40#include "ScriptCompiled.h"
41#include "ScriptCached.h"
42#include "Sha1Helper.h"
43#include "Source.h"
44
45namespace {
46
47bool getBooleanProp(const char *str) {
48 char buf[PROPERTY_VALUE_MAX];
49 property_get(str, buf, "0");
50 return strcmp(buf, "0") != 0;
51}
52
53} // namespace anonymous
54
55namespace bcc {
56
57RSScript::SourceDependency::SourceDependency(MCO_ResourceType pSourceType,
58 const std::string &pSourceName,
59 const uint8_t *pSHA1)
60 : mSourceType(pSourceType), mSourceName(pSourceName) {
61 ::memcpy(mSHA1, pSHA1, sizeof(mSHA1));
62 return;
63}
64
65RSScript::RSScript(Source &pSource)
66 : Script(pSource),
67 mpExtSymbolLookupFn(NULL),
68 mpExtSymbolLookupFnContext(NULL) {
69 resetState();
70 return;
71}
72
73RSScript::~RSScript() {
74 switch (mStatus) {
75 case ScriptStatus::Compiled:
76 delete mCompiled;
77 break;
78
79 case ScriptStatus::Cached:
80 delete mCached;
81 break;
82
83 default:
84 break;
85 }
86 llvm::DeleteContainerPointers(mSourceDependencies);
87}
88
89void RSScript::resetState() {
90 mErrorCode = BCC_NO_ERROR;
91 mStatus = ScriptStatus::Unknown;
92 mObjectType = ScriptObject::Unknown;
93 mIsContextSlotNotAvail = false;
94 // FIXME: mpExtSymbolLookupFn and mpExtSymbolLookupFnContext should be assign
95 // to NULL during state resetting.
96 //mpExtSymbolLookupFn = NULL;
97 //mpExtSymbolLookupFnContext = NULL;
98 llvm::DeleteContainerPointers(mSourceDependencies);
99 return;
100}
101
102
103bool RSScript::doReset() {
104 resetState();
105 return true;
106}
107
108bool RSScript::addSourceDependency(MCO_ResourceType pSourceType,
109 const std::string &pSourceName,
110 const uint8_t *pSHA1) {
111 SourceDependency *source_dep =
112 new (std::nothrow) SourceDependency(pSourceType, pSourceName, pSHA1);
113 if (source_dep == NULL) {
114 ALOGE("Out of memory when record dependency information of `%s'!",
115 pSourceName.c_str());
116 return false;
117 }
118
119 mSourceDependencies.push_back(source_dep);
120 return true;
121}
122
123int RSScript::prepareRelocatable(char const *objPath,
124 llvm::Reloc::Model RelocModel,
125 unsigned long flags) {
126 CompilerOption option;
127 option.RelocModelOpt = RelocModel;
128 option.LoadAfterCompile = false;
129
130 int status = internalCompile(option);
131 if (status != 0) {
132 ALOGE("LLVM error message: %s\n", getCompilerErrorMessage());
133 return status;
134 }
135
136 FileHandle objFile;
137 if (objFile.open(objPath, OpenMode::Write) < 1) {
138 ALOGE("Failed to open %s for write.\n", objPath);
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 FileHandle objFile;
222 if (objFile.open(objPath.c_str(), OpenMode::Read) < 0) {
223 // Unable to open the executable file in read mode.
224 return 1;
225 }
226
227 FileHandle infoFile;
228 if (infoFile.open(infoPath.c_str(), OpenMode::Read) < 0) {
229 // Unable to open the metadata information file in read mode.
230 return 1;
231 }
232
233 MCCacheReader reader;
234
235 // Register symbol lookup function
236 if (mpExtSymbolLookupFn) {
237 reader.registerSymbolCallback(mpExtSymbolLookupFn,
238 mpExtSymbolLookupFnContext);
239 }
240
241 // Dependencies
242 reader.addDependency(BCC_FILE_RESOURCE, pathLibBCC_SHA1, sha1LibBCC_SHA1);
243 reader.addDependency(BCC_FILE_RESOURCE, pathLibRS, sha1LibRS);
244
245 for (unsigned i = 0; i < mSourceDependencies.size(); i++) {
246 const SourceDependency *source_dep = mSourceDependencies[i];
247 reader.addDependency(source_dep->getSourceType(),
248 source_dep->getSourceName(),
249 source_dep->getSHA1Checksum());
250 }
251
252 if (checkOnly)
253 return !reader.checkCacheFile(&objFile, &infoFile, this);
254
255 // Read cache file
256 ScriptCached *cached = reader.readCacheFile(&objFile, &infoFile, this);
257
258 if (!cached) {
259 mIsContextSlotNotAvail = reader.isContextSlotNotAvail();
260 return 1;
261 }
262
263 mCached = cached;
264 mStatus = ScriptStatus::Cached;
265
266 // Dirty hack for libRS.
267 // TODO(all): This dirty hack should be removed in the future.
268 if (!cached->isLibRSThreadable() && mpExtSymbolLookupFn) {
269 mpExtSymbolLookupFn(mpExtSymbolLookupFnContext, "__clearThreadable");
270 }
271
272 return 0;
273}
274
275int RSScript::internalCompile(const CompilerOption &option) {
276 // Create the ScriptCompiled object
277 mCompiled = new (std::nothrow) ScriptCompiled(this);
278
279 if (!mCompiled) {
280 mErrorCode = BCC_OUT_OF_MEMORY;
281 ALOGE("Out of memory: %s %d\n", __FILE__, __LINE__);
282 return 1;
283 }
284
285 mStatus = ScriptStatus::Compiled;
286
287 // Register symbol lookup function
288 if (mpExtSymbolLookupFn) {
289 mCompiled->registerSymbolCallback(mpExtSymbolLookupFn,
290 mpExtSymbolLookupFnContext);
291 }
292
293 // Set the main source module
294 if (mCompiled->readModule(getSource().getModule()) != 0) {
295 ALOGE("Unable to read source module\n");
296 return 1;
297 }
298
299 // Compile and JIT the code
300 if (mCompiled->compile(option) != 0) {
301 ALOGE("Unable to compile.\n");
302 return 1;
303 }
304
305 return 0;
306}
307
308int RSScript::writeCache() {
309 // Not compiled script or encountered error during the compilation.
310 if ((mStatus != ScriptStatus::Compiled) ||
311 (getCompilerErrorMessage() == NULL))
312 return 1;
313
314 // Note: If we re-compile the script because the cached context slot not
315 // available, then we don't have to write the cache.
316
317 // Note: If the address of the context is not in the context slot, then
318 // we don't have to cache it.
319
320 if (isCacheable()) {
321
322 std::string objPath = getCachedObjectPath();
323 std::string infoPath = getCacheInfoPath();
324
325 // Remove the file if it already exists before writing the new file.
326 // The old file may still be mapped elsewhere in memory and we do not want
327 // to modify its contents. (The same script may be running concurrently in
328 // the same process or a different process!)
329 ::unlink(objPath.c_str());
330 ::unlink(infoPath.c_str());
331
332 FileHandle objFile;
333 FileHandle infoFile;
334
335 if (objFile.open(objPath.c_str(), OpenMode::Write) >= 0 &&
336 infoFile.open(infoPath.c_str(), OpenMode::Write) >= 0) {
337
338 MCCacheWriter writer;
339
340#ifdef TARGET_BUILD
341 // Dependencies
342 writer.addDependency(BCC_FILE_RESOURCE, pathLibBCC_SHA1, sha1LibBCC_SHA1);
343 writer.addDependency(BCC_FILE_RESOURCE, pathLibRS, sha1LibRS);
344#endif
345
346 for (unsigned i = 0; i < mSourceDependencies.size(); i++) {
347 const SourceDependency *source_dep = mSourceDependencies[i];
348 writer.addDependency(source_dep->getSourceType(),
349 source_dep->getSourceName(),
350 source_dep->getSHA1Checksum());
351 }
352
353
354 // libRS is threadable dirty hack
355 // TODO: This should be removed in the future
356 uint32_t libRS_threadable = 0;
357 if (mpExtSymbolLookupFn) {
358 libRS_threadable =
359 (uint32_t)mpExtSymbolLookupFn(mpExtSymbolLookupFnContext,
360 "__isThreadable");
361 }
362
363 if (!writer.writeCacheFile(&objFile, &infoFile, this, libRS_threadable)) {
364 objFile.truncate();
365 objFile.close();
366
367 if (unlink(objPath.c_str()) != 0) {
368 ALOGE("Unable to remove the invalid cache file: %s. (reason: %s)\n",
369 objPath.c_str(), strerror(errno));
370 }
371
372 infoFile.truncate();
373 infoFile.close();
374
375 if (unlink(infoPath.c_str()) != 0) {
376 ALOGE("Unable to remove the invalid cache file: %s. (reason: %s)\n",
377 infoPath.c_str(), strerror(errno));
378 }
379 }
380 }
381 }
382
383 return 0;
384}
385
386
387char const *RSScript::getCompilerErrorMessage() {
388 if (mStatus != ScriptStatus::Compiled) {
389 mErrorCode = BCC_INVALID_OPERATION;
390 return NULL;
391 }
392
393 return mCompiled->getCompilerErrorMessage();
394}
395
396
397void *RSScript::lookup(const char *name) {
398 switch (mStatus) {
399 case ScriptStatus::Compiled: {
400 return mCompiled->lookup(name);
401 }
402
403 case ScriptStatus::Cached: {
404 return mCached->lookup(name);
405 }
406
407 default: {
408 mErrorCode = BCC_INVALID_OPERATION;
409 return NULL;
410 }
411 }
412}
413
414
415size_t RSScript::getExportVarCount() const {
416 switch (mStatus) {
417 case ScriptStatus::Compiled: {
418 return mCompiled->getExportVarCount();
419 }
420
421 case ScriptStatus::Cached: {
422 return mCached->getExportVarCount();
423 }
424
425 default: {
426 return 0;
427 }
428 }
429}
430
431
432size_t RSScript::getExportFuncCount() const {
433 switch (mStatus) {
434 case ScriptStatus::Compiled: {
435 return mCompiled->getExportFuncCount();
436 }
437
438 case ScriptStatus::Cached: {
439 return mCached->getExportFuncCount();
440 }
441
442 default: {
443 return 0;
444 }
445 }
446}
447
448
449size_t RSScript::getExportForEachCount() const {
450 switch (mStatus) {
451 case ScriptStatus::Compiled: {
452 return mCompiled->getExportForEachCount();
453 }
454
455 case ScriptStatus::Cached: {
456 return mCached->getExportForEachCount();
457 }
458
459 default: {
460 return 0;
461 }
462 }
463}
464
465
466size_t RSScript::getPragmaCount() const {
467 switch (mStatus) {
468 case ScriptStatus::Compiled: {
469 return mCompiled->getPragmaCount();
470 }
471
472 case ScriptStatus::Cached: {
473 return mCached->getPragmaCount();
474 }
475
476 default: {
477 return 0;
478 }
479 }
480}
481
482
483size_t RSScript::getFuncCount() const {
484 switch (mStatus) {
485 case ScriptStatus::Compiled: {
486 return mCompiled->getFuncCount();
487 }
488
489 case ScriptStatus::Cached: {
490 return mCached->getFuncCount();
491 }
492
493 default: {
494 return 0;
495 }
496 }
497}
498
499
500size_t RSScript::getObjectSlotCount() const {
501 switch (mStatus) {
502 case ScriptStatus::Compiled: {
503 return mCompiled->getObjectSlotCount();
504 }
505
506 case ScriptStatus::Cached: {
507 return mCached->getObjectSlotCount();
508 }
509
510 default: {
511 return 0;
512 }
513 }
514}
515
516
517void RSScript::getExportVarList(size_t varListSize, void **varList) {
518 switch (mStatus) {
519#define DELEGATE(STATUS) \
520 case ScriptStatus::STATUS: \
521 m##STATUS->getExportVarList(varListSize, varList); \
522 break;
523
524 DELEGATE(Cached);
525
526 DELEGATE(Compiled);
527#undef DELEGATE
528
529 default: {
530 mErrorCode = BCC_INVALID_OPERATION;
531 }
532 }
533}
534
535void RSScript::getExportVarNameList(std::vector<std::string> &varList) {
536 switch (mStatus) {
537 case ScriptStatus::Compiled: {
538 return mCompiled->getExportVarNameList(varList);
539 }
540
541 default: {
542 mErrorCode = BCC_INVALID_OPERATION;
543 }
544 }
545}
546
547
548void RSScript::getExportFuncList(size_t funcListSize, void **funcList) {
549 switch (mStatus) {
550#define DELEGATE(STATUS) \
551 case ScriptStatus::STATUS: \
552 m##STATUS->getExportFuncList(funcListSize, funcList); \
553 break;
554
555 DELEGATE(Cached);
556
557 DELEGATE(Compiled);
558#undef DELEGATE
559
560 default: {
561 mErrorCode = BCC_INVALID_OPERATION;
562 }
563 }
564}
565
566void RSScript::getExportFuncNameList(std::vector<std::string> &funcList) {
567 switch (mStatus) {
568 case ScriptStatus::Compiled: {
569 return mCompiled->getExportFuncNameList(funcList);
570 }
571
572 default: {
573 mErrorCode = BCC_INVALID_OPERATION;
574 }
575 }
576}
577
578void RSScript::getExportForEachList(size_t funcListSize, void **funcList) {
579 switch (mStatus) {
580#define DELEGATE(STATUS) \
581 case ScriptStatus::STATUS: \
582 m##STATUS->getExportForEachList(funcListSize, funcList); \
583 break;
584
585 DELEGATE(Cached);
586
587 DELEGATE(Compiled);
588#undef DELEGATE
589
590 default: {
591 mErrorCode = BCC_INVALID_OPERATION;
592 }
593 }
594}
595
596void RSScript::getExportForEachNameList(std::vector<std::string> &forEachList) {
597 switch (mStatus) {
598 case ScriptStatus::Compiled: {
599 return mCompiled->getExportForEachNameList(forEachList);
600 }
601
602 default: {
603 mErrorCode = BCC_INVALID_OPERATION;
604 }
605 }
606}
607
608void RSScript::getPragmaList(size_t pragmaListSize,
609 char const **keyList,
610 char const **valueList) {
611 switch (mStatus) {
612#define DELEGATE(STATUS) \
613 case ScriptStatus::STATUS: \
614 m##STATUS->getPragmaList(pragmaListSize, keyList, valueList); \
615 break;
616
617 DELEGATE(Cached);
618
619 DELEGATE(Compiled);
620#undef DELEGATE
621
622 default: {
623 mErrorCode = BCC_INVALID_OPERATION;
624 }
625 }
626}
627
628
629void RSScript::getFuncInfoList(size_t funcInfoListSize,
630 FuncInfo *funcInfoList) {
631 switch (mStatus) {
632#define DELEGATE(STATUS) \
633 case ScriptStatus::STATUS: \
634 m##STATUS->getFuncInfoList(funcInfoListSize, funcInfoList); \
635 break;
636
637 DELEGATE(Cached);
638
639 DELEGATE(Compiled);
640#undef DELEGATE
641
642 default: {
643 mErrorCode = BCC_INVALID_OPERATION;
644 }
645 }
646}
647
648
649void RSScript::getObjectSlotList(size_t objectSlotListSize,
650 uint32_t *objectSlotList) {
651 switch (mStatus) {
652#define DELEGATE(STATUS) \
653 case ScriptStatus::STATUS: \
654 m##STATUS->getObjectSlotList(objectSlotListSize, objectSlotList); \
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
669int RSScript::registerSymbolCallback(BCCSymbolLookupFn pFn, void *pContext) {
670 mpExtSymbolLookupFn = pFn;
671 mpExtSymbolLookupFnContext = pContext;
672
673 if (mStatus != ScriptStatus::Unknown) {
674 mErrorCode = BCC_INVALID_OPERATION;
675 ALOGE("Invalid operation: %s\n", __func__);
676 return 1;
677 }
678 return 0;
679}
680
681bool RSScript::isCacheable() const {
682 if (getBooleanProp("debug.bcc.nocache")) {
683 // Android system environment property: Disables the cache mechanism by
684 // setting "debug.bcc.nocache". So we will not load the cache file any
685 // way.
686 return false;
687 }
688
689 if (mCacheDir.empty() || mCacheName.empty()) {
690 // The application developer has not specified the cachePath, so
691 // we don't know where to open the cache file.
692 return false;
693 }
694
695 return true;
696}
697
698size_t RSScript::getELFSize() const {
699 switch (mStatus) {
700 case ScriptStatus::Compiled: {
701 return mCompiled->getELFSize();
702 }
703
704 case ScriptStatus::Cached: {
705 return mCached->getELFSize();
706 }
707
708 default: {
709 return 0;
710 }
711 }
712}
713
714const char *RSScript::getELF() const {
715 switch (mStatus) {
716 case ScriptStatus::Compiled: {
717 return mCompiled->getELF();
718 }
719
720 case ScriptStatus::Cached: {
721 return mCached->getELF();
722 }
723
724 default: {
725 return NULL;
726 }
727 }
728}
729
730} // namespace bcc