blob: 789fb013ffaa246270fd3b98a3192bce86c8f900 [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
Logane7eb7732011-01-07 07:11:56 +0800195 CacheReader reader;
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
Logane7eb7732011-01-07 07:11:56 +0800207 ScriptCached *cached = reader.readCacheFile(&file, this);
Logan04329712011-01-06 06:10:57 +0800208 if (!cached) {
209 return 1;
210 }
211
212 mCached = cached;
213 mStatus = ScriptStatus::Cached;
Logan033f46e2011-01-06 05:51:24 +0800214
Loganf3c83ce2011-01-07 06:36:33 +0800215 // Dirty hack for libRS.
216 // TODO(all): This dirty hack should be removed in the future.
217 if (cached->isLibRSThreadable() && mpExtSymbolLookupFn) {
218 mpExtSymbolLookupFn(mpExtSymbolLookupFnContext, "__clearThreadable");
219 }
220
Loganf7f0ac52011-01-07 03:53:43 +0800221 return 0;
Logan033f46e2011-01-06 05:51:24 +0800222}
223
224
225int Script::internalCompile() {
226 // Create the ScriptCompiled object
Loganecf4cbd2011-01-06 05:34:11 +0800227 mCompiled = new (nothrow) ScriptCompiled(this);
228
229 if (!mCompiled) {
230 mErrorCode = BCC_OUT_OF_MEMORY;
231 LOGE("Out of memory: %s %d\n", __FILE__, __LINE__);
232 return 1;
233 }
234
235 mStatus = ScriptStatus::Compiled;
236
Logan033f46e2011-01-06 05:51:24 +0800237 // Register symbol lookup function
Loganecf4cbd2011-01-06 05:34:11 +0800238 if (mpExtSymbolLookupFn) {
239 mCompiled->registerSymbolCallback(mpExtSymbolLookupFn,
240 mpExtSymbolLookupFnContext);
241 }
242
Logan033f46e2011-01-06 05:51:24 +0800243 // Setup the source bitcode / module
Loganecf4cbd2011-01-06 05:34:11 +0800244 if (sourceBC) {
Loganf30a6712011-01-06 05:55:34 +0800245 if (mCompiled->readBC(sourceBC, sourceSize, sourceResName, 0) != 0) {
Logan033f46e2011-01-06 05:51:24 +0800246 return 1;
Loganecf4cbd2011-01-06 05:34:11 +0800247 }
248 } else if (sourceModule) {
Logan033f46e2011-01-06 05:51:24 +0800249 if (mCompiled->readModule(sourceModule) != 0) {
250 return 1;
Loganecf4cbd2011-01-06 05:34:11 +0800251 }
252 }
253
Logan3133c412011-01-06 06:15:40 +0800254 // Link the source module with the library module
Logan04329712011-01-06 06:10:57 +0800255 if (libraryBC) {
256 if (mCompiled->linkBC(libraryBC, librarySize) != 0) {
257 return 1;
258 }
259 }
Loganecf4cbd2011-01-06 05:34:11 +0800260
Logan3133c412011-01-06 06:15:40 +0800261 // Compile and JIT the code
Logan04329712011-01-06 06:10:57 +0800262 if (mCompiled->compile() != 0) {
263 return 1;
264 }
265
266 // TODO(logan): Write the cache out
267#if 0
268 if (cacheFile && !getBooleanProp("debug.bcc.nocache")) {
269 FileHandler file;
270
Logan77124df2011-01-06 06:22:17 +0800271 if (file.open(cacheFile, OpenMode::Write) >= 0) {
Logan04329712011-01-06 06:10:57 +0800272 CacheWriter writer;
273 writer.writeCacheFile(&file);
274 }
275 }
276#endif
277
278 return 0;
Logancf3e5212010-12-29 01:44:55 +0800279}
280
281
282char const *Script::getCompilerErrorMessage() {
283 if (mStatus != ScriptStatus::Compiled) {
284 mErrorCode = BCC_INVALID_OPERATION;
285 return NULL;
286 }
287
288 return mCompiled->getCompilerErrorMessage();
289}
290
291
292void *Script::lookup(const char *name) {
293 if (mStatus != ScriptStatus::Compiled) {
294 mErrorCode = BCC_INVALID_OPERATION;
295 return NULL;
296 }
297
298 return mCompiled->lookup(name);
299}
300
301
302void Script::getExportVars(BCCsizei *actualVarCount,
303 BCCsizei maxVarCount,
304 BCCvoid **vars) {
305 if (mStatus != ScriptStatus::Compiled) {
306 mErrorCode = BCC_INVALID_OPERATION;
307 return;
308 }
309
310 mCompiled->getExportVars(actualVarCount, maxVarCount, vars);
311}
312
313
314void Script::getExportFuncs(BCCsizei *actualFuncCount,
315 BCCsizei maxFuncCount,
316 BCCvoid **funcs) {
317 if (mStatus != ScriptStatus::Compiled) {
318 mErrorCode = BCC_INVALID_OPERATION;
319 return;
320 }
321
322 mCompiled->getExportFuncs(actualFuncCount, maxFuncCount, funcs);
323}
324
325
326void Script::getPragmas(BCCsizei *actualStringCount,
327 BCCsizei maxStringCount,
328 BCCchar **strings) {
329 if (mStatus != ScriptStatus::Compiled) {
330 mErrorCode = BCC_INVALID_OPERATION;
331 return;
332 }
333
334 mCompiled->getPragmas(actualStringCount, maxStringCount, strings);
335}
336
337
338void Script::getFunctions(BCCsizei *actualFunctionCount,
339 BCCsizei maxFunctionCount,
340 BCCchar **functions) {
341 if (mStatus != ScriptStatus::Compiled) {
342 mErrorCode = BCC_INVALID_OPERATION;
343 return;
344 }
345
346 mCompiled->getFunctions(actualFunctionCount, maxFunctionCount, functions);
347}
348
Loganf7f0ac52011-01-07 03:53:43 +0800349char const *Script::getContext() const {
Logan02286cb2011-01-07 00:30:47 +0800350 if (mStatus != ScriptStatus::Compiled) {
351 //mErrorCode = BCC_INVALID_OPERATION;
352 return NULL;
353 }
354
355 return mCompiled->getContext();
356}
357
Logancf3e5212010-12-29 01:44:55 +0800358
359void Script::getFunctionBinary(BCCchar *function,
360 BCCvoid **base,
361 BCCsizei *length) {
362 if (mStatus != ScriptStatus::Compiled) {
363 mErrorCode = BCC_INVALID_OPERATION;
364 return;
365 }
366
367 mCompiled->getFunctionBinary(function, base, length);
368}
369
370
371void Script::registerSymbolCallback(BCCSymbolLookupFn pFn, BCCvoid *pContext) {
372 mpExtSymbolLookupFn = pFn;
373 mpExtSymbolLookupFnContext = pContext;
374
Logan7d2219f2011-01-06 06:19:25 +0800375 if (mStatus != ScriptStatus::Unknown) {
Logancf3e5212010-12-29 01:44:55 +0800376 mErrorCode = BCC_INVALID_OPERATION;
Logan7d2219f2011-01-06 06:19:25 +0800377 LOGE("Invalid operation: %s\n", __func__);
Logancf3e5212010-12-29 01:44:55 +0800378 }
Logancf3e5212010-12-29 01:44:55 +0800379}
380
381} // namespace bcc