blob: 48b75e01de259ca5464242a13bf1cddaa30d1608 [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"
Logan04329712011-01-06 06:10:57 +080026//#include "ScriptCached.h"
Logancf3e5212010-12-29 01:44:55 +080027
28#include <new>
29
Logan033f46e2011-01-06 05:51:24 +080030#include <cutils/properties.h>
31
Loganecf4cbd2011-01-06 05:34:11 +080032namespace {
33
34// Input: cacheDir
35// Input: resName
36// Input: extName
37//
38// Note: cacheFile = resName + extName
39//
40// Output: Returns cachePath == cacheDir + cacheFile
41char *genCacheFileName(const char *cacheDir,
42 const char *resName,
43 const char *extName) {
44 char cachePath[512];
45 char cacheFile[sizeof(cachePath)];
46 const size_t kBufLen = sizeof(cachePath) - 1;
47
48 cacheFile[0] = '\0';
49 // Note: resName today is usually something like
50 // "/com.android.fountain:raw/fountain"
51 if (resName[0] != '/') {
52 // Get the absolute path of the raw/***.bc file.
53
54 // Generate the absolute path. This doesn't do everything it
55 // should, e.g. if resName is "./out/whatever" it doesn't crunch
56 // the leading "./" out because this if-block is not triggered,
57 // but it'll make do.
58 //
59 if (getcwd(cacheFile, kBufLen) == NULL) {
60 LOGE("Can't get CWD while opening raw/***.bc file\n");
61 return NULL;
62 }
63 // Append "/" at the end of cacheFile so far.
64 strncat(cacheFile, "/", kBufLen);
65 }
66
67 // cacheFile = resName + extName
68 //
69 strncat(cacheFile, resName, kBufLen);
70 if (extName != NULL) {
71 // TODO(srhines): strncat() is a bit dangerous
72 strncat(cacheFile, extName, kBufLen);
73 }
74
75 // Turn the path into a flat filename by replacing
76 // any slashes after the first one with '@' characters.
77 char *cp = cacheFile + 1;
78 while (*cp != '\0') {
79 if (*cp == '/') {
80 *cp = '@';
81 }
82 cp++;
83 }
84
85 // Tack on the file name for the actual cache file path.
86 strncpy(cachePath, cacheDir, kBufLen);
87 strncat(cachePath, cacheFile, kBufLen);
88
89 LOGV("Cache file for '%s' '%s' is '%s'\n", resName, extName, cachePath);
90 return strdup(cachePath);
91}
92
Logan033f46e2011-01-06 05:51:24 +080093bool getBooleanProp(const char *str) {
94 char buf[PROPERTY_VALUE_MAX];
95 property_get(str, buf, "0");
96 return strcmp(buf, "0") != 0;
97}
98
Loganecf4cbd2011-01-06 05:34:11 +080099} // namespace anonymous
100
Logancf3e5212010-12-29 01:44:55 +0800101namespace bcc {
102
103Script::~Script() {
104 if (mStatus == ScriptStatus::Compiled) {
105 delete mCompiled;
106 }
107}
108
109
110int Script::readBC(const char *bitcode,
111 size_t bitcodeSize,
Logancf3e5212010-12-29 01:44:55 +0800112 const BCCchar *resName,
113 const BCCchar *cacheDir) {
Loganecf4cbd2011-01-06 05:34:11 +0800114 if (mStatus != ScriptStatus::Unknown) {
Logancf3e5212010-12-29 01:44:55 +0800115 mErrorCode = BCC_INVALID_OPERATION;
Loganecf4cbd2011-01-06 05:34:11 +0800116 LOGE("Invalid operation: %s\n", __func__);
Logancf3e5212010-12-29 01:44:55 +0800117 return 1;
118 }
119
Loganecf4cbd2011-01-06 05:34:11 +0800120 sourceBC = bitcode;
121 sourceResName = resName;
122 sourceSize = bitcodeSize;
123
Logan033f46e2011-01-06 05:51:24 +0800124 if (cacheDir && resName) {
125 cacheFile = genCacheFileName(cacheDir, resName, ".oBCC");
126 }
127
Loganecf4cbd2011-01-06 05:34:11 +0800128 return 0;
Logancf3e5212010-12-29 01:44:55 +0800129}
130
131
132int Script::readModule(llvm::Module *module) {
133 if (mStatus != ScriptStatus::Unknown) {
134 mErrorCode = BCC_INVALID_OPERATION;
Loganecf4cbd2011-01-06 05:34:11 +0800135 LOGE("Invalid operation: %s\n", __func__);
Logancf3e5212010-12-29 01:44:55 +0800136 return 1;
137 }
138
Loganecf4cbd2011-01-06 05:34:11 +0800139 sourceModule = module;
140 return 0;
Logancf3e5212010-12-29 01:44:55 +0800141}
142
143
144int Script::linkBC(const char *bitcode, size_t bitcodeSize) {
Logan3133c412011-01-06 06:15:40 +0800145 if (mStatus != ScriptStatus::Unknown) {
Logancf3e5212010-12-29 01:44:55 +0800146 mErrorCode = BCC_INVALID_OPERATION;
Logan3133c412011-01-06 06:15:40 +0800147 LOGE("Invalid operation: %s\n", __func__);
Logancf3e5212010-12-29 01:44:55 +0800148 return 1;
149 }
150
Logan3133c412011-01-06 06:15:40 +0800151 libraryBC = bitcode;
152 librarySize = bitcodeSize;
153 return 0;
Logancf3e5212010-12-29 01:44:55 +0800154}
155
156
Logancf3e5212010-12-29 01:44:55 +0800157int Script::compile() {
Loganecf4cbd2011-01-06 05:34:11 +0800158 if (mStatus != ScriptStatus::Unknown) {
Logancf3e5212010-12-29 01:44:55 +0800159 mErrorCode = BCC_INVALID_OPERATION;
Loganecf4cbd2011-01-06 05:34:11 +0800160 LOGE("Invalid operation: %s\n", __func__);
Logancf3e5212010-12-29 01:44:55 +0800161 return 1;
162 }
163
Loganecf4cbd2011-01-06 05:34:11 +0800164 // Load Cache File
Logan033f46e2011-01-06 05:51:24 +0800165 if (cacheFile && internalLoadCache() == 0) {
166 return 0;
167 }
Loganecf4cbd2011-01-06 05:34:11 +0800168
Logan033f46e2011-01-06 05:51:24 +0800169 return internalCompile();
170}
171
172
173int Script::internalLoadCache() {
174 if (getBooleanProp("debug.bcc.nocache")) {
175 // Android system environment property disable the cache mechanism by
176 // setting "debug.bcc.nocache". So we will not load the cache file any
177 // way.
178 return 1;
179 }
180
Logan04329712011-01-06 06:10:57 +0800181 if (!cacheFile) {
182 // The application developer has not specify resName or cacheDir, so
183 // we don't know where to open the cache file.
184 return 1;
Logan033f46e2011-01-06 05:51:24 +0800185 }
Logan04329712011-01-06 06:10:57 +0800186
187 FileHandle file;
188
Logan77124df2011-01-06 06:22:17 +0800189 if (file.open(cacheFile, OpenMode::Read) < 0) {
Logan04329712011-01-06 06:10:57 +0800190 // Unable to open the cache file in read mode.
191 return 1;
192 }
193
Loganf7f0ac52011-01-07 03:53:43 +0800194 CacheReader reader(this);
Logan04329712011-01-06 06:10:57 +0800195
196 ScriptCached *cached = reader.readCacheFile(&file);
197 if (!cached) {
198 return 1;
199 }
200
201 mCached = cached;
202 mStatus = ScriptStatus::Cached;
Logan033f46e2011-01-06 05:51:24 +0800203
Loganf7f0ac52011-01-07 03:53:43 +0800204 return 0;
Logan033f46e2011-01-06 05:51:24 +0800205}
206
207
208int Script::internalCompile() {
209 // Create the ScriptCompiled object
Loganecf4cbd2011-01-06 05:34:11 +0800210 mCompiled = new (nothrow) ScriptCompiled(this);
211
212 if (!mCompiled) {
213 mErrorCode = BCC_OUT_OF_MEMORY;
214 LOGE("Out of memory: %s %d\n", __FILE__, __LINE__);
215 return 1;
216 }
217
218 mStatus = ScriptStatus::Compiled;
219
Logan033f46e2011-01-06 05:51:24 +0800220 // Register symbol lookup function
Loganecf4cbd2011-01-06 05:34:11 +0800221 if (mpExtSymbolLookupFn) {
222 mCompiled->registerSymbolCallback(mpExtSymbolLookupFn,
223 mpExtSymbolLookupFnContext);
224 }
225
Logan033f46e2011-01-06 05:51:24 +0800226 // Setup the source bitcode / module
Loganecf4cbd2011-01-06 05:34:11 +0800227 if (sourceBC) {
Loganf30a6712011-01-06 05:55:34 +0800228 if (mCompiled->readBC(sourceBC, sourceSize, sourceResName, 0) != 0) {
Logan033f46e2011-01-06 05:51:24 +0800229 return 1;
Loganecf4cbd2011-01-06 05:34:11 +0800230 }
231 } else if (sourceModule) {
Logan033f46e2011-01-06 05:51:24 +0800232 if (mCompiled->readModule(sourceModule) != 0) {
233 return 1;
Loganecf4cbd2011-01-06 05:34:11 +0800234 }
235 }
236
Logan3133c412011-01-06 06:15:40 +0800237 // Link the source module with the library module
Logan04329712011-01-06 06:10:57 +0800238 if (libraryBC) {
239 if (mCompiled->linkBC(libraryBC, librarySize) != 0) {
240 return 1;
241 }
242 }
Loganecf4cbd2011-01-06 05:34:11 +0800243
Logan3133c412011-01-06 06:15:40 +0800244 // Compile and JIT the code
Logan04329712011-01-06 06:10:57 +0800245 if (mCompiled->compile() != 0) {
246 return 1;
247 }
248
249 // TODO(logan): Write the cache out
250#if 0
251 if (cacheFile && !getBooleanProp("debug.bcc.nocache")) {
252 FileHandler file;
253
Logan77124df2011-01-06 06:22:17 +0800254 if (file.open(cacheFile, OpenMode::Write) >= 0) {
Logan04329712011-01-06 06:10:57 +0800255 CacheWriter writer;
256 writer.writeCacheFile(&file);
257 }
258 }
259#endif
260
261 return 0;
Logancf3e5212010-12-29 01:44:55 +0800262}
263
264
265char const *Script::getCompilerErrorMessage() {
266 if (mStatus != ScriptStatus::Compiled) {
267 mErrorCode = BCC_INVALID_OPERATION;
268 return NULL;
269 }
270
271 return mCompiled->getCompilerErrorMessage();
272}
273
274
275void *Script::lookup(const char *name) {
276 if (mStatus != ScriptStatus::Compiled) {
277 mErrorCode = BCC_INVALID_OPERATION;
278 return NULL;
279 }
280
281 return mCompiled->lookup(name);
282}
283
284
285void Script::getExportVars(BCCsizei *actualVarCount,
286 BCCsizei maxVarCount,
287 BCCvoid **vars) {
288 if (mStatus != ScriptStatus::Compiled) {
289 mErrorCode = BCC_INVALID_OPERATION;
290 return;
291 }
292
293 mCompiled->getExportVars(actualVarCount, maxVarCount, vars);
294}
295
296
297void Script::getExportFuncs(BCCsizei *actualFuncCount,
298 BCCsizei maxFuncCount,
299 BCCvoid **funcs) {
300 if (mStatus != ScriptStatus::Compiled) {
301 mErrorCode = BCC_INVALID_OPERATION;
302 return;
303 }
304
305 mCompiled->getExportFuncs(actualFuncCount, maxFuncCount, funcs);
306}
307
308
309void Script::getPragmas(BCCsizei *actualStringCount,
310 BCCsizei maxStringCount,
311 BCCchar **strings) {
312 if (mStatus != ScriptStatus::Compiled) {
313 mErrorCode = BCC_INVALID_OPERATION;
314 return;
315 }
316
317 mCompiled->getPragmas(actualStringCount, maxStringCount, strings);
318}
319
320
321void Script::getFunctions(BCCsizei *actualFunctionCount,
322 BCCsizei maxFunctionCount,
323 BCCchar **functions) {
324 if (mStatus != ScriptStatus::Compiled) {
325 mErrorCode = BCC_INVALID_OPERATION;
326 return;
327 }
328
329 mCompiled->getFunctions(actualFunctionCount, maxFunctionCount, functions);
330}
331
Loganf7f0ac52011-01-07 03:53:43 +0800332char const *Script::getContext() const {
Logan02286cb2011-01-07 00:30:47 +0800333 if (mStatus != ScriptStatus::Compiled) {
334 //mErrorCode = BCC_INVALID_OPERATION;
335 return NULL;
336 }
337
338 return mCompiled->getContext();
339}
340
Logancf3e5212010-12-29 01:44:55 +0800341
342void Script::getFunctionBinary(BCCchar *function,
343 BCCvoid **base,
344 BCCsizei *length) {
345 if (mStatus != ScriptStatus::Compiled) {
346 mErrorCode = BCC_INVALID_OPERATION;
347 return;
348 }
349
350 mCompiled->getFunctionBinary(function, base, length);
351}
352
353
354void Script::registerSymbolCallback(BCCSymbolLookupFn pFn, BCCvoid *pContext) {
355 mpExtSymbolLookupFn = pFn;
356 mpExtSymbolLookupFnContext = pContext;
357
Logan7d2219f2011-01-06 06:19:25 +0800358 if (mStatus != ScriptStatus::Unknown) {
Logancf3e5212010-12-29 01:44:55 +0800359 mErrorCode = BCC_INVALID_OPERATION;
Logan7d2219f2011-01-06 06:19:25 +0800360 LOGE("Invalid operation: %s\n", __func__);
Logancf3e5212010-12-29 01:44:55 +0800361 }
Logancf3e5212010-12-29 01:44:55 +0800362}
363
364} // namespace bcc