blob: 735b2f77fcbf3f22d65b3ea00ac335dff292dc43 [file] [log] [blame]
Logancf3e5212010-12-29 01:44:55 +08001/*
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#define LOG_TAG "bcc"
18#include <cutils/log.h>
19
20#include "Script.h"
21
Loganf7f0ac52011-01-07 03:53:43 +080022#include "CacheReader.h"
Logan89eb47f2011-01-07 10:45:16 +080023#include "CacheWriter.h"
Logan04329712011-01-06 06:10:57 +080024#include "FileHandle.h"
Logancf3e5212010-12-29 01:44:55 +080025#include "ScriptCompiled.h"
Logan9a5f8682011-01-07 06:09:57 +080026#include "ScriptCached.h"
27#include "Sha1Helper.h"
Logancf3e5212010-12-29 01:44:55 +080028
Logan89eb47f2011-01-07 10:45:16 +080029#include <errno.h>
Logancf3e5212010-12-29 01:44:55 +080030
Logan89eb47f2011-01-07 10:45:16 +080031#include <new>
32#include <string.h>
Logan033f46e2011-01-06 05:51:24 +080033#include <cutils/properties.h>
34
Logan89eb47f2011-01-07 10:45:16 +080035
Loganecf4cbd2011-01-06 05:34:11 +080036namespace {
37
38// Input: cacheDir
39// Input: resName
40// Input: extName
41//
42// Note: cacheFile = resName + extName
43//
44// Output: Returns cachePath == cacheDir + cacheFile
45char *genCacheFileName(const char *cacheDir,
46 const char *resName,
47 const char *extName) {
48 char cachePath[512];
49 char cacheFile[sizeof(cachePath)];
50 const size_t kBufLen = sizeof(cachePath) - 1;
51
52 cacheFile[0] = '\0';
53 // Note: resName today is usually something like
54 // "/com.android.fountain:raw/fountain"
55 if (resName[0] != '/') {
56 // Get the absolute path of the raw/***.bc file.
57
58 // Generate the absolute path. This doesn't do everything it
59 // should, e.g. if resName is "./out/whatever" it doesn't crunch
60 // the leading "./" out because this if-block is not triggered,
61 // but it'll make do.
62 //
63 if (getcwd(cacheFile, kBufLen) == NULL) {
64 LOGE("Can't get CWD while opening raw/***.bc file\n");
65 return NULL;
66 }
67 // Append "/" at the end of cacheFile so far.
68 strncat(cacheFile, "/", kBufLen);
69 }
70
71 // cacheFile = resName + extName
72 //
73 strncat(cacheFile, resName, kBufLen);
74 if (extName != NULL) {
75 // TODO(srhines): strncat() is a bit dangerous
76 strncat(cacheFile, extName, kBufLen);
77 }
78
79 // Turn the path into a flat filename by replacing
80 // any slashes after the first one with '@' characters.
81 char *cp = cacheFile + 1;
82 while (*cp != '\0') {
83 if (*cp == '/') {
84 *cp = '@';
85 }
86 cp++;
87 }
88
89 // Tack on the file name for the actual cache file path.
90 strncpy(cachePath, cacheDir, kBufLen);
91 strncat(cachePath, cacheFile, kBufLen);
92
93 LOGV("Cache file for '%s' '%s' is '%s'\n", resName, extName, cachePath);
94 return strdup(cachePath);
95}
96
Logan033f46e2011-01-06 05:51:24 +080097bool getBooleanProp(const char *str) {
98 char buf[PROPERTY_VALUE_MAX];
99 property_get(str, buf, "0");
100 return strcmp(buf, "0") != 0;
101}
102
Loganecf4cbd2011-01-06 05:34:11 +0800103} // namespace anonymous
104
Logancf3e5212010-12-29 01:44:55 +0800105namespace bcc {
106
107Script::~Script() {
108 if (mStatus == ScriptStatus::Compiled) {
109 delete mCompiled;
Shih-wei Liaoc4cf6542011-01-13 01:43:01 -0800110 } else if (mStatus == ScriptStatus::Cached) {
111 delete mCached;
Logancf3e5212010-12-29 01:44:55 +0800112 }
113}
114
115
116int Script::readBC(const char *bitcode,
117 size_t bitcodeSize,
Logancf3e5212010-12-29 01:44:55 +0800118 const BCCchar *resName,
119 const BCCchar *cacheDir) {
Loganecf4cbd2011-01-06 05:34:11 +0800120 if (mStatus != ScriptStatus::Unknown) {
Logancf3e5212010-12-29 01:44:55 +0800121 mErrorCode = BCC_INVALID_OPERATION;
Loganecf4cbd2011-01-06 05:34:11 +0800122 LOGE("Invalid operation: %s\n", __func__);
Logancf3e5212010-12-29 01:44:55 +0800123 return 1;
124 }
125
Loganecf4cbd2011-01-06 05:34:11 +0800126 sourceBC = bitcode;
127 sourceResName = resName;
128 sourceSize = bitcodeSize;
129
Logan033f46e2011-01-06 05:51:24 +0800130 if (cacheDir && resName) {
131 cacheFile = genCacheFileName(cacheDir, resName, ".oBCC");
132 }
133
Loganecf4cbd2011-01-06 05:34:11 +0800134 return 0;
Logancf3e5212010-12-29 01:44:55 +0800135}
136
137
138int Script::readModule(llvm::Module *module) {
139 if (mStatus != ScriptStatus::Unknown) {
140 mErrorCode = BCC_INVALID_OPERATION;
Loganecf4cbd2011-01-06 05:34:11 +0800141 LOGE("Invalid operation: %s\n", __func__);
Logancf3e5212010-12-29 01:44:55 +0800142 return 1;
143 }
144
Loganecf4cbd2011-01-06 05:34:11 +0800145 sourceModule = module;
146 return 0;
Logancf3e5212010-12-29 01:44:55 +0800147}
148
149
150int Script::linkBC(const char *bitcode, size_t bitcodeSize) {
Logan3133c412011-01-06 06:15:40 +0800151 if (mStatus != ScriptStatus::Unknown) {
Logancf3e5212010-12-29 01:44:55 +0800152 mErrorCode = BCC_INVALID_OPERATION;
Logan3133c412011-01-06 06:15:40 +0800153 LOGE("Invalid operation: %s\n", __func__);
Logancf3e5212010-12-29 01:44:55 +0800154 return 1;
155 }
156
Logan3133c412011-01-06 06:15:40 +0800157 libraryBC = bitcode;
158 librarySize = bitcodeSize;
Shih-wei Liaoc4cf6542011-01-13 01:43:01 -0800159 LOGI("libraryBC = %x, librarySize = %d", libraryBC, librarySize);
Logan3133c412011-01-06 06:15:40 +0800160 return 0;
Logancf3e5212010-12-29 01:44:55 +0800161}
162
163
Loganbe79ada2011-01-13 01:33:45 +0800164int Script::prepareExecutable() {
Loganecf4cbd2011-01-06 05:34:11 +0800165 if (mStatus != ScriptStatus::Unknown) {
Logancf3e5212010-12-29 01:44:55 +0800166 mErrorCode = BCC_INVALID_OPERATION;
Loganecf4cbd2011-01-06 05:34:11 +0800167 LOGE("Invalid operation: %s\n", __func__);
Logancf3e5212010-12-29 01:44:55 +0800168 return 1;
169 }
170
Loganecf4cbd2011-01-06 05:34:11 +0800171 // Load Cache File
Logan033f46e2011-01-06 05:51:24 +0800172 if (cacheFile && internalLoadCache() == 0) {
173 return 0;
174 }
Loganecf4cbd2011-01-06 05:34:11 +0800175
Logan033f46e2011-01-06 05:51:24 +0800176 return internalCompile();
177}
178
179
180int Script::internalLoadCache() {
181 if (getBooleanProp("debug.bcc.nocache")) {
182 // Android system environment property disable the cache mechanism by
183 // setting "debug.bcc.nocache". So we will not load the cache file any
184 // way.
185 return 1;
186 }
187
Logan04329712011-01-06 06:10:57 +0800188 if (!cacheFile) {
189 // The application developer has not specify resName or cacheDir, so
190 // we don't know where to open the cache file.
191 return 1;
Logan033f46e2011-01-06 05:51:24 +0800192 }
Logan04329712011-01-06 06:10:57 +0800193
Logana2e15af2011-01-07 11:46:08 +0800194 if (sourceBC) {
195 // If we are going to create cache file. We have to calculate sha1sum
196 // first (no matter we can open the file now or not.)
197 calcSHA1(sourceSHA1, sourceBC, sourceSize);
198 }
199
Logan04329712011-01-06 06:10:57 +0800200 FileHandle file;
201
Logan77124df2011-01-06 06:22:17 +0800202 if (file.open(cacheFile, OpenMode::Read) < 0) {
Logan04329712011-01-06 06:10:57 +0800203 // Unable to open the cache file in read mode.
204 return 1;
205 }
206
Logane7eb7732011-01-07 07:11:56 +0800207 CacheReader reader;
Logan04329712011-01-06 06:10:57 +0800208
Logan9a5f8682011-01-07 06:09:57 +0800209 // Dependencies
Logane1323992011-01-12 04:47:13 +0800210#if defined(USE_LIBBCC_SHA1SUM)
Logan9a5f8682011-01-07 06:09:57 +0800211 reader.addDependency(BCC_FILE_RESOURCE, pathLibBCC, sha1LibBCC);
Logane1323992011-01-12 04:47:13 +0800212#endif
213
Logan9a5f8682011-01-07 06:09:57 +0800214 reader.addDependency(BCC_FILE_RESOURCE, pathLibRS, sha1LibRS);
215
216 if (sourceBC) {
Logan9a5f8682011-01-07 06:09:57 +0800217 reader.addDependency(BCC_APK_RESOURCE, sourceResName, sourceSHA1);
218 }
219
220 // Read cache file
Logane7eb7732011-01-07 07:11:56 +0800221 ScriptCached *cached = reader.readCacheFile(&file, this);
Logan04329712011-01-06 06:10:57 +0800222 if (!cached) {
223 return 1;
224 }
225
226 mCached = cached;
227 mStatus = ScriptStatus::Cached;
Logan033f46e2011-01-06 05:51:24 +0800228
Loganf3c83ce2011-01-07 06:36:33 +0800229 // Dirty hack for libRS.
230 // TODO(all): This dirty hack should be removed in the future.
231 if (cached->isLibRSThreadable() && mpExtSymbolLookupFn) {
232 mpExtSymbolLookupFn(mpExtSymbolLookupFnContext, "__clearThreadable");
233 }
234
Loganf7f0ac52011-01-07 03:53:43 +0800235 return 0;
Logan033f46e2011-01-06 05:51:24 +0800236}
237
238
239int Script::internalCompile() {
240 // Create the ScriptCompiled object
Loganecf4cbd2011-01-06 05:34:11 +0800241 mCompiled = new (nothrow) ScriptCompiled(this);
242
243 if (!mCompiled) {
244 mErrorCode = BCC_OUT_OF_MEMORY;
245 LOGE("Out of memory: %s %d\n", __FILE__, __LINE__);
246 return 1;
247 }
248
249 mStatus = ScriptStatus::Compiled;
250
Logan033f46e2011-01-06 05:51:24 +0800251 // Register symbol lookup function
Loganecf4cbd2011-01-06 05:34:11 +0800252 if (mpExtSymbolLookupFn) {
253 mCompiled->registerSymbolCallback(mpExtSymbolLookupFn,
254 mpExtSymbolLookupFnContext);
255 }
256
Logan033f46e2011-01-06 05:51:24 +0800257 // Setup the source bitcode / module
Loganecf4cbd2011-01-06 05:34:11 +0800258 if (sourceBC) {
Loganf30a6712011-01-06 05:55:34 +0800259 if (mCompiled->readBC(sourceBC, sourceSize, sourceResName, 0) != 0) {
Logan65719812011-01-07 11:17:14 +0800260 LOGE("Unable to readBC, bitcode=%p, size=%lu\n",
261 sourceBC, (unsigned long)sourceSize);
Logan033f46e2011-01-06 05:51:24 +0800262 return 1;
Loganecf4cbd2011-01-06 05:34:11 +0800263 }
Logan65719812011-01-07 11:17:14 +0800264
Shih-wei Liaoefbd0ed2011-01-07 06:36:25 -0800265 LOGI("Load sourceBC\n");
Loganecf4cbd2011-01-06 05:34:11 +0800266 } else if (sourceModule) {
Logan033f46e2011-01-06 05:51:24 +0800267 if (mCompiled->readModule(sourceModule) != 0) {
268 return 1;
Loganecf4cbd2011-01-06 05:34:11 +0800269 }
Logan65719812011-01-07 11:17:14 +0800270
Shih-wei Liaoefbd0ed2011-01-07 06:36:25 -0800271 LOGI("Load sourceModule\n");
Loganecf4cbd2011-01-06 05:34:11 +0800272 }
273
Logan3133c412011-01-06 06:15:40 +0800274 // Link the source module with the library module
Logan04329712011-01-06 06:10:57 +0800275 if (libraryBC) {
276 if (mCompiled->linkBC(libraryBC, librarySize) != 0) {
277 return 1;
278 }
Logan65719812011-01-07 11:17:14 +0800279
280 LOGE("Load Library\n");
Logan04329712011-01-06 06:10:57 +0800281 }
Loganecf4cbd2011-01-06 05:34:11 +0800282
Logan3133c412011-01-06 06:15:40 +0800283 // Compile and JIT the code
Logan04329712011-01-06 06:10:57 +0800284 if (mCompiled->compile() != 0) {
Logan65719812011-01-07 11:17:14 +0800285 LOGE("Unable to compile.\n");
Logan04329712011-01-06 06:10:57 +0800286 return 1;
287 }
288
289 // TODO(logan): Write the cache out
Logan04329712011-01-06 06:10:57 +0800290 if (cacheFile && !getBooleanProp("debug.bcc.nocache")) {
Logan89eb47f2011-01-07 10:45:16 +0800291 FileHandle file;
Logan04329712011-01-06 06:10:57 +0800292
Logan77124df2011-01-06 06:22:17 +0800293 if (file.open(cacheFile, OpenMode::Write) >= 0) {
Logan04329712011-01-06 06:10:57 +0800294 CacheWriter writer;
Logana27a83f2011-01-07 10:25:48 +0800295
Logana2e15af2011-01-07 11:46:08 +0800296 // Dependencies
Logane1323992011-01-12 04:47:13 +0800297#if defined(USE_LIBBCC_SHA1SUM)
Logana2e15af2011-01-07 11:46:08 +0800298 writer.addDependency(BCC_FILE_RESOURCE, pathLibBCC, sha1LibBCC);
Logane1323992011-01-12 04:47:13 +0800299#endif
Logana2e15af2011-01-07 11:46:08 +0800300 writer.addDependency(BCC_FILE_RESOURCE, pathLibRS, sha1LibRS);
301
302 if (sourceBC) {
303 writer.addDependency(BCC_APK_RESOURCE, sourceResName, sourceSHA1);
304 }
305
Logana27a83f2011-01-07 10:25:48 +0800306 // libRS is threadable dirty hack
307 // TODO: This should be removed in the future
308 uint32_t libRS_threadable = 0;
309 if (mpExtSymbolLookupFn) {
Logan89eb47f2011-01-07 10:45:16 +0800310 libRS_threadable =
311 (uint32_t)mpExtSymbolLookupFn(mpExtSymbolLookupFnContext,
312 "__isThreadable");
Logana27a83f2011-01-07 10:25:48 +0800313 }
314
Logan89eb47f2011-01-07 10:45:16 +0800315 if (!writer.writeCacheFile(&file, this, libRS_threadable)) {
316 file.truncate();
317 file.close();
Logana27a83f2011-01-07 10:25:48 +0800318
Logan89eb47f2011-01-07 10:45:16 +0800319 if (unlink(cacheFile) != 0) {
320 LOGE("Unable to remove the invalid cache file: %s. (reason: %s)\n",
321 cacheFile, strerror(errno));
322 }
323 }
324 }
Logan04329712011-01-06 06:10:57 +0800325 }
Logan04329712011-01-06 06:10:57 +0800326
327 return 0;
Logancf3e5212010-12-29 01:44:55 +0800328}
329
330
331char const *Script::getCompilerErrorMessage() {
332 if (mStatus != ScriptStatus::Compiled) {
333 mErrorCode = BCC_INVALID_OPERATION;
334 return NULL;
335 }
336
337 return mCompiled->getCompilerErrorMessage();
338}
339
340
341void *Script::lookup(const char *name) {
Logan89eb47f2011-01-07 10:45:16 +0800342 switch (mStatus) {
Loganbe79ada2011-01-13 01:33:45 +0800343 case ScriptStatus::Compiled: return mCompiled->lookup(name);
344 case ScriptStatus::Cached: return mCached->lookup(name);
Logan89eb47f2011-01-07 10:45:16 +0800345
346 default:
Logancf3e5212010-12-29 01:44:55 +0800347 mErrorCode = BCC_INVALID_OPERATION;
348 return NULL;
349 }
Logancf3e5212010-12-29 01:44:55 +0800350}
351
352
Loganbe79ada2011-01-13 01:33:45 +0800353size_t Script::getExportVarCount() const {
Logan89eb47f2011-01-07 10:45:16 +0800354 switch (mStatus) {
Loganbe79ada2011-01-13 01:33:45 +0800355 case ScriptStatus::Compiled: return mCompiled->getExportVarCount();
356 case ScriptStatus::Cached: return mCached->getExportVarCount();
357 default: return 0;
358 }
359}
360
361
362size_t Script::getExportFuncCount() const {
363 switch (mStatus) {
364 case ScriptStatus::Compiled: return mCompiled->getExportFuncCount();
365 case ScriptStatus::Cached: return mCached->getExportFuncCount();
366 default: return 0;
367 }
368}
369
370
371size_t Script::getPragmaCount() const {
372 switch (mStatus) {
373 case ScriptStatus::Compiled: return mCompiled->getPragmaCount();
374 case ScriptStatus::Cached: return mCached->getPragmaCount();
375 default: return 0;
376 }
377}
378
379
380size_t Script::getFuncCount() const {
381 switch (mStatus) {
382 case ScriptStatus::Compiled: return mCompiled->getFuncCount();
383 case ScriptStatus::Cached: return mCached->getFuncCount();
384 default: return 0;
385 }
386}
387
388
389void Script::getExportVarList(size_t varListSize, void **varList) {
390 switch (mStatus) {
391#define DELEGATE(STATUS) \
392 case ScriptStatus::STATUS: \
393 m##STATUS->getExportVarList(varListSize, varList); \
Logan89eb47f2011-01-07 10:45:16 +0800394 break;
Logancf3e5212010-12-29 01:44:55 +0800395
Loganbe79ada2011-01-13 01:33:45 +0800396 DELEGATE(Cached);
397 DELEGATE(Compiled);
398#undef DELEGATE
Logan89eb47f2011-01-07 10:45:16 +0800399
400 default:
401 mErrorCode = BCC_INVALID_OPERATION;
402 }
Logancf3e5212010-12-29 01:44:55 +0800403}
404
405
Loganbe79ada2011-01-13 01:33:45 +0800406void Script::getExportFuncList(size_t funcListSize, void **funcList) {
Logan89eb47f2011-01-07 10:45:16 +0800407 switch (mStatus) {
Loganbe79ada2011-01-13 01:33:45 +0800408#define DELEGATE(STATUS) \
409 case ScriptStatus::STATUS: \
410 m##STATUS->getExportFuncList(funcListSize, funcList); \
Logan89eb47f2011-01-07 10:45:16 +0800411 break;
Logancf3e5212010-12-29 01:44:55 +0800412
Loganbe79ada2011-01-13 01:33:45 +0800413 DELEGATE(Cached);
414 DELEGATE(Compiled);
415#undef DELEGATE
Logan89eb47f2011-01-07 10:45:16 +0800416
417 default:
418 mErrorCode = BCC_INVALID_OPERATION;
419 }
Logancf3e5212010-12-29 01:44:55 +0800420}
421
422
Loganbe79ada2011-01-13 01:33:45 +0800423void Script::getPragmaList(size_t pragmaListSize,
424 char const **keyList,
425 char const **valueList) {
Logan89eb47f2011-01-07 10:45:16 +0800426 switch (mStatus) {
Loganbe79ada2011-01-13 01:33:45 +0800427#define DELEGATE(STATUS) \
428 case ScriptStatus::STATUS: \
429 m##STATUS->getPragmaList(pragmaListSize, keyList, valueList); \
Logan89eb47f2011-01-07 10:45:16 +0800430 break;
Logancf3e5212010-12-29 01:44:55 +0800431
Loganbe79ada2011-01-13 01:33:45 +0800432 DELEGATE(Cached);
433 DELEGATE(Compiled);
434#undef DELEGATE
Logan89eb47f2011-01-07 10:45:16 +0800435
436 default:
437 mErrorCode = BCC_INVALID_OPERATION;
438 }
Logancf3e5212010-12-29 01:44:55 +0800439}
440
441
Loganbe79ada2011-01-13 01:33:45 +0800442void Script::getFuncNameList(size_t funcNameListSize,
443 char const **funcNameList) {
Logan89eb47f2011-01-07 10:45:16 +0800444 switch (mStatus) {
Loganbe79ada2011-01-13 01:33:45 +0800445#define DELEGATE(STATUS) \
446 case ScriptStatus::STATUS: \
447 m##STATUS->getFuncNameList(funcNameListSize, funcNameList);
Logan89eb47f2011-01-07 10:45:16 +0800448 break;
Logancf3e5212010-12-29 01:44:55 +0800449
Loganbe79ada2011-01-13 01:33:45 +0800450 DELEGATE(Cached);
451 DELEGATE(Compiled);
452#undef DELEGATE
Logan89eb47f2011-01-07 10:45:16 +0800453
454 default:
455 mErrorCode = BCC_INVALID_OPERATION;
456 }
Logancf3e5212010-12-29 01:44:55 +0800457}
458
Logana27a83f2011-01-07 10:25:48 +0800459char *Script::getContext() {
460 switch (mStatus) {
Loganbe79ada2011-01-13 01:33:45 +0800461 case ScriptStatus::Cached: return mCached->getContext();
462 case ScriptStatus::Compiled: return mCompiled->getContext();
Logana27a83f2011-01-07 10:25:48 +0800463
464 default:
465 mErrorCode = BCC_INVALID_OPERATION;
Logan02286cb2011-01-07 00:30:47 +0800466 return NULL;
467 }
Logan02286cb2011-01-07 00:30:47 +0800468}
469
Logancf3e5212010-12-29 01:44:55 +0800470
Loganbe79ada2011-01-13 01:33:45 +0800471void Script::getFuncBinary(char const *funcname,
472 void **base,
473 size_t *length) {
Logan216ec712011-01-07 12:12:31 +0800474 switch (mStatus) {
Loganbe79ada2011-01-13 01:33:45 +0800475#define DELEGATE(STATUS) \
476 case ScriptStatus::STATUS: \
477 m##STATUS->getFuncBinary(funcname, base, length); \
478 break;
Logan216ec712011-01-07 12:12:31 +0800479
Loganbe79ada2011-01-13 01:33:45 +0800480 DELEGATE(Cached);
481 DELEGATE(Compiled);
482#undef DELEGATE
Logan216ec712011-01-07 12:12:31 +0800483
484 default:
485 *base = NULL;
486 *length = 0;
Logancf3e5212010-12-29 01:44:55 +0800487 }
Logancf3e5212010-12-29 01:44:55 +0800488}
489
490
491void Script::registerSymbolCallback(BCCSymbolLookupFn pFn, BCCvoid *pContext) {
492 mpExtSymbolLookupFn = pFn;
493 mpExtSymbolLookupFnContext = pContext;
494
Logan7d2219f2011-01-06 06:19:25 +0800495 if (mStatus != ScriptStatus::Unknown) {
Logancf3e5212010-12-29 01:44:55 +0800496 mErrorCode = BCC_INVALID_OPERATION;
Logan7d2219f2011-01-06 06:19:25 +0800497 LOGE("Invalid operation: %s\n", __func__);
Logancf3e5212010-12-29 01:44:55 +0800498 }
Logancf3e5212010-12-29 01:44:55 +0800499}
500
501} // namespace bcc