blob: a59407b0cf200ba9fc57e1ee938c6d0f2174da1d [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"
Logan04329712011-01-06 06:10:57 +080023//#include "CacheWriter.h"
24#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
29#include <new>
30
Logan033f46e2011-01-06 05:51:24 +080031#include <cutils/properties.h>
32
Loganecf4cbd2011-01-06 05:34:11 +080033namespace {
34
35// Input: cacheDir
36// Input: resName
37// Input: extName
38//
39// Note: cacheFile = resName + extName
40//
41// Output: Returns cachePath == cacheDir + cacheFile
42char *genCacheFileName(const char *cacheDir,
43 const char *resName,
44 const char *extName) {
45 char cachePath[512];
46 char cacheFile[sizeof(cachePath)];
47 const size_t kBufLen = sizeof(cachePath) - 1;
48
49 cacheFile[0] = '\0';
50 // Note: resName today is usually something like
51 // "/com.android.fountain:raw/fountain"
52 if (resName[0] != '/') {
53 // Get the absolute path of the raw/***.bc file.
54
55 // Generate the absolute path. This doesn't do everything it
56 // should, e.g. if resName is "./out/whatever" it doesn't crunch
57 // the leading "./" out because this if-block is not triggered,
58 // but it'll make do.
59 //
60 if (getcwd(cacheFile, kBufLen) == NULL) {
61 LOGE("Can't get CWD while opening raw/***.bc file\n");
62 return NULL;
63 }
64 // Append "/" at the end of cacheFile so far.
65 strncat(cacheFile, "/", kBufLen);
66 }
67
68 // cacheFile = resName + extName
69 //
70 strncat(cacheFile, resName, kBufLen);
71 if (extName != NULL) {
72 // TODO(srhines): strncat() is a bit dangerous
73 strncat(cacheFile, extName, kBufLen);
74 }
75
76 // Turn the path into a flat filename by replacing
77 // any slashes after the first one with '@' characters.
78 char *cp = cacheFile + 1;
79 while (*cp != '\0') {
80 if (*cp == '/') {
81 *cp = '@';
82 }
83 cp++;
84 }
85
86 // Tack on the file name for the actual cache file path.
87 strncpy(cachePath, cacheDir, kBufLen);
88 strncat(cachePath, cacheFile, kBufLen);
89
90 LOGV("Cache file for '%s' '%s' is '%s'\n", resName, extName, cachePath);
91 return strdup(cachePath);
92}
93
Logan033f46e2011-01-06 05:51:24 +080094bool getBooleanProp(const char *str) {
95 char buf[PROPERTY_VALUE_MAX];
96 property_get(str, buf, "0");
97 return strcmp(buf, "0") != 0;
98}
99
Loganecf4cbd2011-01-06 05:34:11 +0800100} // namespace anonymous
101
Logancf3e5212010-12-29 01:44:55 +0800102namespace bcc {
103
104Script::~Script() {
105 if (mStatus == ScriptStatus::Compiled) {
106 delete mCompiled;
107 }
108}
109
110
111int Script::readBC(const char *bitcode,
112 size_t bitcodeSize,
Logancf3e5212010-12-29 01:44:55 +0800113 const BCCchar *resName,
114 const BCCchar *cacheDir) {
Loganecf4cbd2011-01-06 05:34:11 +0800115 if (mStatus != ScriptStatus::Unknown) {
Logancf3e5212010-12-29 01:44:55 +0800116 mErrorCode = BCC_INVALID_OPERATION;
Loganecf4cbd2011-01-06 05:34:11 +0800117 LOGE("Invalid operation: %s\n", __func__);
Logancf3e5212010-12-29 01:44:55 +0800118 return 1;
119 }
120
Loganecf4cbd2011-01-06 05:34:11 +0800121 sourceBC = bitcode;
122 sourceResName = resName;
123 sourceSize = bitcodeSize;
124
Logan033f46e2011-01-06 05:51:24 +0800125 if (cacheDir && resName) {
126 cacheFile = genCacheFileName(cacheDir, resName, ".oBCC");
127 }
128
Loganecf4cbd2011-01-06 05:34:11 +0800129 return 0;
Logancf3e5212010-12-29 01:44:55 +0800130}
131
132
133int Script::readModule(llvm::Module *module) {
134 if (mStatus != ScriptStatus::Unknown) {
135 mErrorCode = BCC_INVALID_OPERATION;
Loganecf4cbd2011-01-06 05:34:11 +0800136 LOGE("Invalid operation: %s\n", __func__);
Logancf3e5212010-12-29 01:44:55 +0800137 return 1;
138 }
139
Loganecf4cbd2011-01-06 05:34:11 +0800140 sourceModule = module;
141 return 0;
Logancf3e5212010-12-29 01:44:55 +0800142}
143
144
145int Script::linkBC(const char *bitcode, size_t bitcodeSize) {
Logan3133c412011-01-06 06:15:40 +0800146 if (mStatus != ScriptStatus::Unknown) {
Logancf3e5212010-12-29 01:44:55 +0800147 mErrorCode = BCC_INVALID_OPERATION;
Logan3133c412011-01-06 06:15:40 +0800148 LOGE("Invalid operation: %s\n", __func__);
Logancf3e5212010-12-29 01:44:55 +0800149 return 1;
150 }
151
Logan3133c412011-01-06 06:15:40 +0800152 libraryBC = bitcode;
153 librarySize = bitcodeSize;
154 return 0;
Logancf3e5212010-12-29 01:44:55 +0800155}
156
157
Logancf3e5212010-12-29 01:44:55 +0800158int Script::compile() {
Loganecf4cbd2011-01-06 05:34:11 +0800159 if (mStatus != ScriptStatus::Unknown) {
Logancf3e5212010-12-29 01:44:55 +0800160 mErrorCode = BCC_INVALID_OPERATION;
Loganecf4cbd2011-01-06 05:34:11 +0800161 LOGE("Invalid operation: %s\n", __func__);
Logancf3e5212010-12-29 01:44:55 +0800162 return 1;
163 }
164
Loganecf4cbd2011-01-06 05:34:11 +0800165 // Load Cache File
Logan033f46e2011-01-06 05:51:24 +0800166 if (cacheFile && internalLoadCache() == 0) {
167 return 0;
168 }
Loganecf4cbd2011-01-06 05:34:11 +0800169
Logan033f46e2011-01-06 05:51:24 +0800170 return internalCompile();
171}
172
173
174int Script::internalLoadCache() {
175 if (getBooleanProp("debug.bcc.nocache")) {
176 // Android system environment property disable the cache mechanism by
177 // setting "debug.bcc.nocache". So we will not load the cache file any
178 // way.
179 return 1;
180 }
181
Logan04329712011-01-06 06:10:57 +0800182 if (!cacheFile) {
183 // The application developer has not specify resName or cacheDir, so
184 // we don't know where to open the cache file.
185 return 1;
Logan033f46e2011-01-06 05:51:24 +0800186 }
Logan04329712011-01-06 06:10:57 +0800187
188 FileHandle file;
189
Logan77124df2011-01-06 06:22:17 +0800190 if (file.open(cacheFile, OpenMode::Read) < 0) {
Logan04329712011-01-06 06:10:57 +0800191 // Unable to open the cache file in read mode.
192 return 1;
193 }
194
Loganf7f0ac52011-01-07 03:53:43 +0800195 CacheReader reader(this);
Logan04329712011-01-06 06:10:57 +0800196
Logan9a5f8682011-01-07 06:09:57 +0800197 // Dependencies
198 reader.addDependency(BCC_FILE_RESOURCE, pathLibBCC, sha1LibBCC);
199 reader.addDependency(BCC_FILE_RESOURCE, pathLibRS, sha1LibRS);
200
201 if (sourceBC) {
202 calcSHA1(sourceSHA1, sourceBC, sourceSize);
203 reader.addDependency(BCC_APK_RESOURCE, sourceResName, sourceSHA1);
204 }
205
206 // Read cache file
Logan04329712011-01-06 06:10:57 +0800207 ScriptCached *cached = reader.readCacheFile(&file);
208 if (!cached) {
209 return 1;
210 }
211
212 mCached = cached;
213 mStatus = ScriptStatus::Cached;
Logan033f46e2011-01-06 05:51:24 +0800214
Loganf7f0ac52011-01-07 03:53:43 +0800215 return 0;
Logan033f46e2011-01-06 05:51:24 +0800216}
217
218
219int Script::internalCompile() {
220 // Create the ScriptCompiled object
Loganecf4cbd2011-01-06 05:34:11 +0800221 mCompiled = new (nothrow) ScriptCompiled(this);
222
223 if (!mCompiled) {
224 mErrorCode = BCC_OUT_OF_MEMORY;
225 LOGE("Out of memory: %s %d\n", __FILE__, __LINE__);
226 return 1;
227 }
228
229 mStatus = ScriptStatus::Compiled;
230
Logan033f46e2011-01-06 05:51:24 +0800231 // Register symbol lookup function
Loganecf4cbd2011-01-06 05:34:11 +0800232 if (mpExtSymbolLookupFn) {
233 mCompiled->registerSymbolCallback(mpExtSymbolLookupFn,
234 mpExtSymbolLookupFnContext);
235 }
236
Logan033f46e2011-01-06 05:51:24 +0800237 // Setup the source bitcode / module
Loganecf4cbd2011-01-06 05:34:11 +0800238 if (sourceBC) {
Loganf30a6712011-01-06 05:55:34 +0800239 if (mCompiled->readBC(sourceBC, sourceSize, sourceResName, 0) != 0) {
Logan033f46e2011-01-06 05:51:24 +0800240 return 1;
Loganecf4cbd2011-01-06 05:34:11 +0800241 }
242 } else if (sourceModule) {
Logan033f46e2011-01-06 05:51:24 +0800243 if (mCompiled->readModule(sourceModule) != 0) {
244 return 1;
Loganecf4cbd2011-01-06 05:34:11 +0800245 }
246 }
247
Logan3133c412011-01-06 06:15:40 +0800248 // Link the source module with the library module
Logan04329712011-01-06 06:10:57 +0800249 if (libraryBC) {
250 if (mCompiled->linkBC(libraryBC, librarySize) != 0) {
251 return 1;
252 }
253 }
Loganecf4cbd2011-01-06 05:34:11 +0800254
Logan3133c412011-01-06 06:15:40 +0800255 // Compile and JIT the code
Logan04329712011-01-06 06:10:57 +0800256 if (mCompiled->compile() != 0) {
257 return 1;
258 }
259
260 // TODO(logan): Write the cache out
261#if 0
262 if (cacheFile && !getBooleanProp("debug.bcc.nocache")) {
263 FileHandler file;
264
Logan77124df2011-01-06 06:22:17 +0800265 if (file.open(cacheFile, OpenMode::Write) >= 0) {
Logan04329712011-01-06 06:10:57 +0800266 CacheWriter writer;
267 writer.writeCacheFile(&file);
268 }
269 }
270#endif
271
272 return 0;
Logancf3e5212010-12-29 01:44:55 +0800273}
274
275
276char const *Script::getCompilerErrorMessage() {
277 if (mStatus != ScriptStatus::Compiled) {
278 mErrorCode = BCC_INVALID_OPERATION;
279 return NULL;
280 }
281
282 return mCompiled->getCompilerErrorMessage();
283}
284
285
286void *Script::lookup(const char *name) {
287 if (mStatus != ScriptStatus::Compiled) {
288 mErrorCode = BCC_INVALID_OPERATION;
289 return NULL;
290 }
291
292 return mCompiled->lookup(name);
293}
294
295
296void Script::getExportVars(BCCsizei *actualVarCount,
297 BCCsizei maxVarCount,
298 BCCvoid **vars) {
299 if (mStatus != ScriptStatus::Compiled) {
300 mErrorCode = BCC_INVALID_OPERATION;
301 return;
302 }
303
304 mCompiled->getExportVars(actualVarCount, maxVarCount, vars);
305}
306
307
308void Script::getExportFuncs(BCCsizei *actualFuncCount,
309 BCCsizei maxFuncCount,
310 BCCvoid **funcs) {
311 if (mStatus != ScriptStatus::Compiled) {
312 mErrorCode = BCC_INVALID_OPERATION;
313 return;
314 }
315
316 mCompiled->getExportFuncs(actualFuncCount, maxFuncCount, funcs);
317}
318
319
320void Script::getPragmas(BCCsizei *actualStringCount,
321 BCCsizei maxStringCount,
322 BCCchar **strings) {
323 if (mStatus != ScriptStatus::Compiled) {
324 mErrorCode = BCC_INVALID_OPERATION;
325 return;
326 }
327
328 mCompiled->getPragmas(actualStringCount, maxStringCount, strings);
329}
330
331
332void Script::getFunctions(BCCsizei *actualFunctionCount,
333 BCCsizei maxFunctionCount,
334 BCCchar **functions) {
335 if (mStatus != ScriptStatus::Compiled) {
336 mErrorCode = BCC_INVALID_OPERATION;
337 return;
338 }
339
340 mCompiled->getFunctions(actualFunctionCount, maxFunctionCount, functions);
341}
342
Loganf7f0ac52011-01-07 03:53:43 +0800343char const *Script::getContext() const {
Logan02286cb2011-01-07 00:30:47 +0800344 if (mStatus != ScriptStatus::Compiled) {
345 //mErrorCode = BCC_INVALID_OPERATION;
346 return NULL;
347 }
348
349 return mCompiled->getContext();
350}
351
Logancf3e5212010-12-29 01:44:55 +0800352
353void Script::getFunctionBinary(BCCchar *function,
354 BCCvoid **base,
355 BCCsizei *length) {
356 if (mStatus != ScriptStatus::Compiled) {
357 mErrorCode = BCC_INVALID_OPERATION;
358 return;
359 }
360
361 mCompiled->getFunctionBinary(function, base, length);
362}
363
364
365void Script::registerSymbolCallback(BCCSymbolLookupFn pFn, BCCvoid *pContext) {
366 mpExtSymbolLookupFn = pFn;
367 mpExtSymbolLookupFnContext = pContext;
368
Logan7d2219f2011-01-06 06:19:25 +0800369 if (mStatus != ScriptStatus::Unknown) {
Logancf3e5212010-12-29 01:44:55 +0800370 mErrorCode = BCC_INVALID_OPERATION;
Logan7d2219f2011-01-06 06:19:25 +0800371 LOGE("Invalid operation: %s\n", __func__);
Logancf3e5212010-12-29 01:44:55 +0800372 }
Logancf3e5212010-12-29 01:44:55 +0800373}
374
375} // namespace bcc