blob: c6ccfa1c3e39c2be6cd1b0b6d98be7a5cc2449e2 [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;
110 }
111}
112
113
114int Script::readBC(const char *bitcode,
115 size_t bitcodeSize,
Logancf3e5212010-12-29 01:44:55 +0800116 const BCCchar *resName,
117 const BCCchar *cacheDir) {
Loganecf4cbd2011-01-06 05:34:11 +0800118 if (mStatus != ScriptStatus::Unknown) {
Logancf3e5212010-12-29 01:44:55 +0800119 mErrorCode = BCC_INVALID_OPERATION;
Loganecf4cbd2011-01-06 05:34:11 +0800120 LOGE("Invalid operation: %s\n", __func__);
Logancf3e5212010-12-29 01:44:55 +0800121 return 1;
122 }
123
Loganecf4cbd2011-01-06 05:34:11 +0800124 sourceBC = bitcode;
125 sourceResName = resName;
126 sourceSize = bitcodeSize;
127
Logan033f46e2011-01-06 05:51:24 +0800128 if (cacheDir && resName) {
129 cacheFile = genCacheFileName(cacheDir, resName, ".oBCC");
130 }
131
Loganecf4cbd2011-01-06 05:34:11 +0800132 return 0;
Logancf3e5212010-12-29 01:44:55 +0800133}
134
135
136int Script::readModule(llvm::Module *module) {
137 if (mStatus != ScriptStatus::Unknown) {
138 mErrorCode = BCC_INVALID_OPERATION;
Loganecf4cbd2011-01-06 05:34:11 +0800139 LOGE("Invalid operation: %s\n", __func__);
Logancf3e5212010-12-29 01:44:55 +0800140 return 1;
141 }
142
Loganecf4cbd2011-01-06 05:34:11 +0800143 sourceModule = module;
144 return 0;
Logancf3e5212010-12-29 01:44:55 +0800145}
146
147
148int Script::linkBC(const char *bitcode, size_t bitcodeSize) {
Logan3133c412011-01-06 06:15:40 +0800149 if (mStatus != ScriptStatus::Unknown) {
Logancf3e5212010-12-29 01:44:55 +0800150 mErrorCode = BCC_INVALID_OPERATION;
Logan3133c412011-01-06 06:15:40 +0800151 LOGE("Invalid operation: %s\n", __func__);
Logancf3e5212010-12-29 01:44:55 +0800152 return 1;
153 }
154
Logan3133c412011-01-06 06:15:40 +0800155 libraryBC = bitcode;
156 librarySize = bitcodeSize;
157 return 0;
Logancf3e5212010-12-29 01:44:55 +0800158}
159
160
Logancf3e5212010-12-29 01:44:55 +0800161int Script::compile() {
Loganecf4cbd2011-01-06 05:34:11 +0800162 if (mStatus != ScriptStatus::Unknown) {
Logancf3e5212010-12-29 01:44:55 +0800163 mErrorCode = BCC_INVALID_OPERATION;
Loganecf4cbd2011-01-06 05:34:11 +0800164 LOGE("Invalid operation: %s\n", __func__);
Logancf3e5212010-12-29 01:44:55 +0800165 return 1;
166 }
167
Loganecf4cbd2011-01-06 05:34:11 +0800168 // Load Cache File
Logan033f46e2011-01-06 05:51:24 +0800169 if (cacheFile && internalLoadCache() == 0) {
170 return 0;
171 }
Loganecf4cbd2011-01-06 05:34:11 +0800172
Logan033f46e2011-01-06 05:51:24 +0800173 return internalCompile();
174}
175
176
177int Script::internalLoadCache() {
178 if (getBooleanProp("debug.bcc.nocache")) {
179 // Android system environment property disable the cache mechanism by
180 // setting "debug.bcc.nocache". So we will not load the cache file any
181 // way.
182 return 1;
183 }
184
Logan04329712011-01-06 06:10:57 +0800185 if (!cacheFile) {
186 // The application developer has not specify resName or cacheDir, so
187 // we don't know where to open the cache file.
188 return 1;
Logan033f46e2011-01-06 05:51:24 +0800189 }
Logan04329712011-01-06 06:10:57 +0800190
191 FileHandle file;
192
Logan77124df2011-01-06 06:22:17 +0800193 if (file.open(cacheFile, OpenMode::Read) < 0) {
Logan04329712011-01-06 06:10:57 +0800194 // Unable to open the cache file in read mode.
195 return 1;
196 }
197
Logane7eb7732011-01-07 07:11:56 +0800198 CacheReader reader;
Logan04329712011-01-06 06:10:57 +0800199
Logan9a5f8682011-01-07 06:09:57 +0800200 // Dependencies
201 reader.addDependency(BCC_FILE_RESOURCE, pathLibBCC, sha1LibBCC);
202 reader.addDependency(BCC_FILE_RESOURCE, pathLibRS, sha1LibRS);
203
204 if (sourceBC) {
205 calcSHA1(sourceSHA1, sourceBC, sourceSize);
206 reader.addDependency(BCC_APK_RESOURCE, sourceResName, sourceSHA1);
207 }
208
209 // Read cache file
Logane7eb7732011-01-07 07:11:56 +0800210 ScriptCached *cached = reader.readCacheFile(&file, this);
Logan04329712011-01-06 06:10:57 +0800211 if (!cached) {
212 return 1;
213 }
214
215 mCached = cached;
216 mStatus = ScriptStatus::Cached;
Logan033f46e2011-01-06 05:51:24 +0800217
Loganf3c83ce2011-01-07 06:36:33 +0800218 // Dirty hack for libRS.
219 // TODO(all): This dirty hack should be removed in the future.
220 if (cached->isLibRSThreadable() && mpExtSymbolLookupFn) {
221 mpExtSymbolLookupFn(mpExtSymbolLookupFnContext, "__clearThreadable");
222 }
223
Loganf7f0ac52011-01-07 03:53:43 +0800224 return 0;
Logan033f46e2011-01-06 05:51:24 +0800225}
226
227
228int Script::internalCompile() {
229 // Create the ScriptCompiled object
Loganecf4cbd2011-01-06 05:34:11 +0800230 mCompiled = new (nothrow) ScriptCompiled(this);
231
232 if (!mCompiled) {
233 mErrorCode = BCC_OUT_OF_MEMORY;
234 LOGE("Out of memory: %s %d\n", __FILE__, __LINE__);
235 return 1;
236 }
237
238 mStatus = ScriptStatus::Compiled;
239
Logan033f46e2011-01-06 05:51:24 +0800240 // Register symbol lookup function
Loganecf4cbd2011-01-06 05:34:11 +0800241 if (mpExtSymbolLookupFn) {
242 mCompiled->registerSymbolCallback(mpExtSymbolLookupFn,
243 mpExtSymbolLookupFnContext);
244 }
245
Logan033f46e2011-01-06 05:51:24 +0800246 // Setup the source bitcode / module
Loganecf4cbd2011-01-06 05:34:11 +0800247 if (sourceBC) {
Loganf30a6712011-01-06 05:55:34 +0800248 if (mCompiled->readBC(sourceBC, sourceSize, sourceResName, 0) != 0) {
Logan65719812011-01-07 11:17:14 +0800249 LOGE("Unable to readBC, bitcode=%p, size=%lu\n",
250 sourceBC, (unsigned long)sourceSize);
Logan033f46e2011-01-06 05:51:24 +0800251 return 1;
Loganecf4cbd2011-01-06 05:34:11 +0800252 }
Logan65719812011-01-07 11:17:14 +0800253
254 LOGE("Load sourceBC\n");
Loganecf4cbd2011-01-06 05:34:11 +0800255 } else if (sourceModule) {
Logan033f46e2011-01-06 05:51:24 +0800256 if (mCompiled->readModule(sourceModule) != 0) {
257 return 1;
Loganecf4cbd2011-01-06 05:34:11 +0800258 }
Logan65719812011-01-07 11:17:14 +0800259
260 LOGE("Load sourceModule\n");
Loganecf4cbd2011-01-06 05:34:11 +0800261 }
262
Logan3133c412011-01-06 06:15:40 +0800263 // Link the source module with the library module
Logan04329712011-01-06 06:10:57 +0800264 if (libraryBC) {
265 if (mCompiled->linkBC(libraryBC, librarySize) != 0) {
266 return 1;
267 }
Logan65719812011-01-07 11:17:14 +0800268
269 LOGE("Load Library\n");
Logan04329712011-01-06 06:10:57 +0800270 }
Loganecf4cbd2011-01-06 05:34:11 +0800271
Logan3133c412011-01-06 06:15:40 +0800272 // Compile and JIT the code
Logan04329712011-01-06 06:10:57 +0800273 if (mCompiled->compile() != 0) {
Logan65719812011-01-07 11:17:14 +0800274 LOGE("Unable to compile.\n");
Logan04329712011-01-06 06:10:57 +0800275 return 1;
276 }
277
278 // TODO(logan): Write the cache out
Logan04329712011-01-06 06:10:57 +0800279 if (cacheFile && !getBooleanProp("debug.bcc.nocache")) {
Logan89eb47f2011-01-07 10:45:16 +0800280 FileHandle file;
Logan04329712011-01-06 06:10:57 +0800281
Logan77124df2011-01-06 06:22:17 +0800282 if (file.open(cacheFile, OpenMode::Write) >= 0) {
Logan04329712011-01-06 06:10:57 +0800283 CacheWriter writer;
Logana27a83f2011-01-07 10:25:48 +0800284
285 // libRS is threadable dirty hack
286 // TODO: This should be removed in the future
287 uint32_t libRS_threadable = 0;
288 if (mpExtSymbolLookupFn) {
Logan89eb47f2011-01-07 10:45:16 +0800289 libRS_threadable =
290 (uint32_t)mpExtSymbolLookupFn(mpExtSymbolLookupFnContext,
291 "__isThreadable");
Logana27a83f2011-01-07 10:25:48 +0800292 }
293
Logan89eb47f2011-01-07 10:45:16 +0800294 if (!writer.writeCacheFile(&file, this, libRS_threadable)) {
295 file.truncate();
296 file.close();
Logana27a83f2011-01-07 10:25:48 +0800297
Logan89eb47f2011-01-07 10:45:16 +0800298 if (unlink(cacheFile) != 0) {
299 LOGE("Unable to remove the invalid cache file: %s. (reason: %s)\n",
300 cacheFile, strerror(errno));
301 }
302 }
303 }
Logan04329712011-01-06 06:10:57 +0800304 }
Logan04329712011-01-06 06:10:57 +0800305
306 return 0;
Logancf3e5212010-12-29 01:44:55 +0800307}
308
309
310char const *Script::getCompilerErrorMessage() {
311 if (mStatus != ScriptStatus::Compiled) {
312 mErrorCode = BCC_INVALID_OPERATION;
313 return NULL;
314 }
315
316 return mCompiled->getCompilerErrorMessage();
317}
318
319
320void *Script::lookup(const char *name) {
Logan89eb47f2011-01-07 10:45:16 +0800321 switch (mStatus) {
322 case ScriptStatus::Compiled:
323 return mCompiled->lookup(name);
324
325 case ScriptStatus::Cached:
326 return mCached->lookup(name);
327
328 default:
Logancf3e5212010-12-29 01:44:55 +0800329 mErrorCode = BCC_INVALID_OPERATION;
330 return NULL;
331 }
Logancf3e5212010-12-29 01:44:55 +0800332}
333
334
335void Script::getExportVars(BCCsizei *actualVarCount,
336 BCCsizei maxVarCount,
337 BCCvoid **vars) {
Logan89eb47f2011-01-07 10:45:16 +0800338 switch (mStatus) {
339 case ScriptStatus::Compiled:
340 mCompiled->getExportVars(actualVarCount, maxVarCount, vars);
341 break;
Logancf3e5212010-12-29 01:44:55 +0800342
Logan89eb47f2011-01-07 10:45:16 +0800343 case ScriptStatus::Cached:
344 mCached->getExportVars(actualVarCount, maxVarCount, vars);
345 break;
346
347 default:
348 mErrorCode = BCC_INVALID_OPERATION;
349 }
Logancf3e5212010-12-29 01:44:55 +0800350}
351
352
353void Script::getExportFuncs(BCCsizei *actualFuncCount,
354 BCCsizei maxFuncCount,
355 BCCvoid **funcs) {
Logan89eb47f2011-01-07 10:45:16 +0800356 switch (mStatus) {
357 case ScriptStatus::Compiled:
358 mCompiled->getExportFuncs(actualFuncCount, maxFuncCount, funcs);
359 break;
Logancf3e5212010-12-29 01:44:55 +0800360
Logan89eb47f2011-01-07 10:45:16 +0800361 case ScriptStatus::Cached:
362 mCached->getExportFuncs(actualFuncCount, maxFuncCount, funcs);
363 break;
364
365 default:
366 mErrorCode = BCC_INVALID_OPERATION;
367 }
Logancf3e5212010-12-29 01:44:55 +0800368}
369
370
371void Script::getPragmas(BCCsizei *actualStringCount,
372 BCCsizei maxStringCount,
373 BCCchar **strings) {
Logan89eb47f2011-01-07 10:45:16 +0800374 switch (mStatus) {
375 case ScriptStatus::Compiled:
376 mCompiled->getPragmas(actualStringCount, maxStringCount, strings);
377 break;
Logancf3e5212010-12-29 01:44:55 +0800378
Logan89eb47f2011-01-07 10:45:16 +0800379 case ScriptStatus::Cached:
380 mCached->getPragmas(actualStringCount, maxStringCount, strings);
381 break;
382
383 default:
384 mErrorCode = BCC_INVALID_OPERATION;
385 }
Logancf3e5212010-12-29 01:44:55 +0800386}
387
388
389void Script::getFunctions(BCCsizei *actualFunctionCount,
390 BCCsizei maxFunctionCount,
391 BCCchar **functions) {
Logan89eb47f2011-01-07 10:45:16 +0800392 switch (mStatus) {
393 case ScriptStatus::Compiled:
394 mCompiled->getFunctions(actualFunctionCount, maxFunctionCount, functions);
395 break;
Logancf3e5212010-12-29 01:44:55 +0800396
Logan89eb47f2011-01-07 10:45:16 +0800397 case ScriptStatus::Cached:
398 mCached->getFunctions(actualFunctionCount, maxFunctionCount, functions);
399 break;
400
401 default:
402 mErrorCode = BCC_INVALID_OPERATION;
403 }
Logancf3e5212010-12-29 01:44:55 +0800404}
405
Logana27a83f2011-01-07 10:25:48 +0800406char *Script::getContext() {
407 switch (mStatus) {
408 case ScriptStatus::Compiled:
409 return mCompiled->getContext();
410
411 case ScriptStatus::Cached:
412 return mCached->getContext();
413
414 default:
415 mErrorCode = BCC_INVALID_OPERATION;
Logan02286cb2011-01-07 00:30:47 +0800416 return NULL;
417 }
Logan02286cb2011-01-07 00:30:47 +0800418}
419
Logancf3e5212010-12-29 01:44:55 +0800420
421void Script::getFunctionBinary(BCCchar *function,
422 BCCvoid **base,
423 BCCsizei *length) {
424 if (mStatus != ScriptStatus::Compiled) {
425 mErrorCode = BCC_INVALID_OPERATION;
426 return;
427 }
428
429 mCompiled->getFunctionBinary(function, base, length);
430}
431
432
433void Script::registerSymbolCallback(BCCSymbolLookupFn pFn, BCCvoid *pContext) {
434 mpExtSymbolLookupFn = pFn;
435 mpExtSymbolLookupFnContext = pContext;
436
Logan7d2219f2011-01-06 06:19:25 +0800437 if (mStatus != ScriptStatus::Unknown) {
Logancf3e5212010-12-29 01:44:55 +0800438 mErrorCode = BCC_INVALID_OPERATION;
Logan7d2219f2011-01-06 06:19:25 +0800439 LOGE("Invalid operation: %s\n", __func__);
Logancf3e5212010-12-29 01:44:55 +0800440 }
Logancf3e5212010-12-29 01:44:55 +0800441}
442
443} // namespace bcc