blob: 318a68d9c8ab96e04d613aecb0b91cbe8edc1a6f [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"
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 // Sanitize 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 if (isCacheable()) {
315
316 std::string objPath = getCachedObjectPath();
317 std::string infoPath = getCacheInfoPath();
318
319 // Remove the file if it already exists before writing the new file.
320 // The old file may still be mapped elsewhere in memory and we do not want
321 // to modify its contents. (The same script may be running concurrently in
322 // the same process or a different process!)
323 ::unlink(objPath.c_str());
324 ::unlink(infoPath.c_str());
325
326 FileHandle objFile;
327 FileHandle infoFile;
328
329 if (objFile.open(objPath.c_str(), OpenMode::Write) >= 0 &&
330 infoFile.open(infoPath.c_str(), OpenMode::Write) >= 0) {
331
332 MCCacheWriter writer;
333
334#ifdef TARGET_BUILD
335 // Dependencies
336 writer.addDependency(BCC_FILE_RESOURCE, pathLibBCC_SHA1, sha1LibBCC_SHA1);
337 writer.addDependency(BCC_FILE_RESOURCE, pathLibRS, sha1LibRS);
338#endif
339
340 for (unsigned i = 0; i < mSourceDependencies.size(); i++) {
341 const SourceDependency *source_dep = mSourceDependencies[i];
342 writer.addDependency(source_dep->getSourceType(),
343 source_dep->getSourceName(),
344 source_dep->getSHA1Checksum());
345 }
346
347
348 // libRS is threadable dirty hack
349 // TODO: This should be removed in the future
350 uint32_t libRS_threadable = 0;
351 if (mpExtSymbolLookupFn) {
352 libRS_threadable =
353 (uint32_t)mpExtSymbolLookupFn(mpExtSymbolLookupFnContext,
354 "__isThreadable");
355 }
356
357 if (!writer.writeCacheFile(&objFile, &infoFile, this, libRS_threadable)) {
358 objFile.truncate();
359 objFile.close();
360
361 if (unlink(objPath.c_str()) != 0) {
362 ALOGE("Unable to remove the invalid cache file: %s. (reason: %s)\n",
363 objPath.c_str(), strerror(errno));
364 }
365
366 infoFile.truncate();
367 infoFile.close();
368
369 if (unlink(infoPath.c_str()) != 0) {
370 ALOGE("Unable to remove the invalid cache file: %s. (reason: %s)\n",
371 infoPath.c_str(), strerror(errno));
372 }
373 }
374 }
375 }
376
377 return 0;
378}
379
380
381char const *RSScript::getCompilerErrorMessage() {
382 if (mStatus != ScriptStatus::Compiled) {
383 mErrorCode = BCC_INVALID_OPERATION;
384 return NULL;
385 }
386
387 return mCompiled->getCompilerErrorMessage();
388}
389
390
391void *RSScript::lookup(const char *name) {
392 switch (mStatus) {
393 case ScriptStatus::Compiled: {
394 return mCompiled->lookup(name);
395 }
396
397 case ScriptStatus::Cached: {
398 return mCached->lookup(name);
399 }
400
401 default: {
402 mErrorCode = BCC_INVALID_OPERATION;
403 return NULL;
404 }
405 }
406}
407
408
409size_t RSScript::getExportVarCount() const {
410 switch (mStatus) {
411 case ScriptStatus::Compiled: {
412 return mCompiled->getExportVarCount();
413 }
414
415 case ScriptStatus::Cached: {
416 return mCached->getExportVarCount();
417 }
418
419 default: {
420 return 0;
421 }
422 }
423}
424
425
426size_t RSScript::getExportFuncCount() const {
427 switch (mStatus) {
428 case ScriptStatus::Compiled: {
429 return mCompiled->getExportFuncCount();
430 }
431
432 case ScriptStatus::Cached: {
433 return mCached->getExportFuncCount();
434 }
435
436 default: {
437 return 0;
438 }
439 }
440}
441
442
443size_t RSScript::getExportForEachCount() const {
444 switch (mStatus) {
445 case ScriptStatus::Compiled: {
446 return mCompiled->getExportForEachCount();
447 }
448
449 case ScriptStatus::Cached: {
450 return mCached->getExportForEachCount();
451 }
452
453 default: {
454 return 0;
455 }
456 }
457}
458
459
460size_t RSScript::getPragmaCount() const {
461 switch (mStatus) {
462 case ScriptStatus::Compiled: {
463 return mCompiled->getPragmaCount();
464 }
465
466 case ScriptStatus::Cached: {
467 return mCached->getPragmaCount();
468 }
469
470 default: {
471 return 0;
472 }
473 }
474}
475
476
477size_t RSScript::getFuncCount() const {
478 switch (mStatus) {
479 case ScriptStatus::Compiled: {
480 return mCompiled->getFuncCount();
481 }
482
483 case ScriptStatus::Cached: {
484 return mCached->getFuncCount();
485 }
486
487 default: {
488 return 0;
489 }
490 }
491}
492
493
494size_t RSScript::getObjectSlotCount() const {
495 switch (mStatus) {
496 case ScriptStatus::Compiled: {
497 return mCompiled->getObjectSlotCount();
498 }
499
500 case ScriptStatus::Cached: {
501 return mCached->getObjectSlotCount();
502 }
503
504 default: {
505 return 0;
506 }
507 }
508}
509
510
511void RSScript::getExportVarList(size_t varListSize, void **varList) {
512 switch (mStatus) {
513#define DELEGATE(STATUS) \
514 case ScriptStatus::STATUS: \
515 m##STATUS->getExportVarList(varListSize, varList); \
516 break;
517
518 DELEGATE(Cached);
519
520 DELEGATE(Compiled);
521#undef DELEGATE
522
523 default: {
524 mErrorCode = BCC_INVALID_OPERATION;
525 }
526 }
527}
528
529void RSScript::getExportVarNameList(std::vector<std::string> &varList) {
530 switch (mStatus) {
531 case ScriptStatus::Compiled: {
532 return mCompiled->getExportVarNameList(varList);
533 }
534
535 default: {
536 mErrorCode = BCC_INVALID_OPERATION;
537 }
538 }
539}
540
541
542void RSScript::getExportFuncList(size_t funcListSize, void **funcList) {
543 switch (mStatus) {
544#define DELEGATE(STATUS) \
545 case ScriptStatus::STATUS: \
546 m##STATUS->getExportFuncList(funcListSize, funcList); \
547 break;
548
549 DELEGATE(Cached);
550
551 DELEGATE(Compiled);
552#undef DELEGATE
553
554 default: {
555 mErrorCode = BCC_INVALID_OPERATION;
556 }
557 }
558}
559
560void RSScript::getExportFuncNameList(std::vector<std::string> &funcList) {
561 switch (mStatus) {
562 case ScriptStatus::Compiled: {
563 return mCompiled->getExportFuncNameList(funcList);
564 }
565
566 default: {
567 mErrorCode = BCC_INVALID_OPERATION;
568 }
569 }
570}
571
572void RSScript::getExportForEachList(size_t funcListSize, void **funcList) {
573 switch (mStatus) {
574#define DELEGATE(STATUS) \
575 case ScriptStatus::STATUS: \
576 m##STATUS->getExportForEachList(funcListSize, funcList); \
577 break;
578
579 DELEGATE(Cached);
580
581 DELEGATE(Compiled);
582#undef DELEGATE
583
584 default: {
585 mErrorCode = BCC_INVALID_OPERATION;
586 }
587 }
588}
589
590void RSScript::getExportForEachNameList(std::vector<std::string> &forEachList) {
591 switch (mStatus) {
592 case ScriptStatus::Compiled: {
593 return mCompiled->getExportForEachNameList(forEachList);
594 }
595
596 default: {
597 mErrorCode = BCC_INVALID_OPERATION;
598 }
599 }
600}
601
602void RSScript::getPragmaList(size_t pragmaListSize,
603 char const **keyList,
604 char const **valueList) {
605 switch (mStatus) {
606#define DELEGATE(STATUS) \
607 case ScriptStatus::STATUS: \
608 m##STATUS->getPragmaList(pragmaListSize, keyList, valueList); \
609 break;
610
611 DELEGATE(Cached);
612
613 DELEGATE(Compiled);
614#undef DELEGATE
615
616 default: {
617 mErrorCode = BCC_INVALID_OPERATION;
618 }
619 }
620}
621
622
623void RSScript::getFuncInfoList(size_t funcInfoListSize,
624 FuncInfo *funcInfoList) {
625 switch (mStatus) {
626#define DELEGATE(STATUS) \
627 case ScriptStatus::STATUS: \
628 m##STATUS->getFuncInfoList(funcInfoListSize, funcInfoList); \
629 break;
630
631 DELEGATE(Cached);
632
633 DELEGATE(Compiled);
634#undef DELEGATE
635
636 default: {
637 mErrorCode = BCC_INVALID_OPERATION;
638 }
639 }
640}
641
642
643void RSScript::getObjectSlotList(size_t objectSlotListSize,
644 uint32_t *objectSlotList) {
645 switch (mStatus) {
646#define DELEGATE(STATUS) \
647 case ScriptStatus::STATUS: \
648 m##STATUS->getObjectSlotList(objectSlotListSize, objectSlotList); \
649 break;
650
651 DELEGATE(Cached);
652
653 DELEGATE(Compiled);
654#undef DELEGATE
655
656 default: {
657 mErrorCode = BCC_INVALID_OPERATION;
658 }
659 }
660}
661
662
663int RSScript::registerSymbolCallback(BCCSymbolLookupFn pFn, void *pContext) {
664 mpExtSymbolLookupFn = pFn;
665 mpExtSymbolLookupFnContext = pContext;
666
667 if (mStatus != ScriptStatus::Unknown) {
668 mErrorCode = BCC_INVALID_OPERATION;
669 ALOGE("Invalid operation: %s\n", __func__);
670 return 1;
671 }
672 return 0;
673}
674
675bool RSScript::isCacheable() const {
676 if (getBooleanProp("debug.bcc.nocache")) {
677 // Android system environment property: Disables the cache mechanism by
678 // setting "debug.bcc.nocache". So we will not load the cache file any
679 // way.
680 return false;
681 }
682
683 if (mCacheDir.empty() || mCacheName.empty()) {
684 // The application developer has not specified the cachePath, so
685 // we don't know where to open the cache file.
686 return false;
687 }
688
689 return true;
690}
691
692size_t RSScript::getELFSize() const {
693 switch (mStatus) {
694 case ScriptStatus::Compiled: {
695 return mCompiled->getELFSize();
696 }
697
698 case ScriptStatus::Cached: {
699 return mCached->getELFSize();
700 }
701
702 default: {
703 return 0;
704 }
705 }
706}
707
708const char *RSScript::getELF() const {
709 switch (mStatus) {
710 case ScriptStatus::Compiled: {
711 return mCompiled->getELF();
712 }
713
714 case ScriptStatus::Cached: {
715 return mCached->getELF();
716 }
717
718 default: {
719 return NULL;
720 }
721 }
722}
723
724} // namespace bcc