blob: 2520bdcd597c273a4c4c222d8c1140c9e4604473 [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
22#include "ScriptCompiled.h"
23
24#include <new>
25
Logan033f46e2011-01-06 05:51:24 +080026#include <cutils/properties.h>
27
Loganecf4cbd2011-01-06 05:34:11 +080028namespace {
29
30// Input: cacheDir
31// Input: resName
32// Input: extName
33//
34// Note: cacheFile = resName + extName
35//
36// Output: Returns cachePath == cacheDir + cacheFile
37char *genCacheFileName(const char *cacheDir,
38 const char *resName,
39 const char *extName) {
40 char cachePath[512];
41 char cacheFile[sizeof(cachePath)];
42 const size_t kBufLen = sizeof(cachePath) - 1;
43
44 cacheFile[0] = '\0';
45 // Note: resName today is usually something like
46 // "/com.android.fountain:raw/fountain"
47 if (resName[0] != '/') {
48 // Get the absolute path of the raw/***.bc file.
49
50 // Generate the absolute path. This doesn't do everything it
51 // should, e.g. if resName is "./out/whatever" it doesn't crunch
52 // the leading "./" out because this if-block is not triggered,
53 // but it'll make do.
54 //
55 if (getcwd(cacheFile, kBufLen) == NULL) {
56 LOGE("Can't get CWD while opening raw/***.bc file\n");
57 return NULL;
58 }
59 // Append "/" at the end of cacheFile so far.
60 strncat(cacheFile, "/", kBufLen);
61 }
62
63 // cacheFile = resName + extName
64 //
65 strncat(cacheFile, resName, kBufLen);
66 if (extName != NULL) {
67 // TODO(srhines): strncat() is a bit dangerous
68 strncat(cacheFile, extName, kBufLen);
69 }
70
71 // Turn the path into a flat filename by replacing
72 // any slashes after the first one with '@' characters.
73 char *cp = cacheFile + 1;
74 while (*cp != '\0') {
75 if (*cp == '/') {
76 *cp = '@';
77 }
78 cp++;
79 }
80
81 // Tack on the file name for the actual cache file path.
82 strncpy(cachePath, cacheDir, kBufLen);
83 strncat(cachePath, cacheFile, kBufLen);
84
85 LOGV("Cache file for '%s' '%s' is '%s'\n", resName, extName, cachePath);
86 return strdup(cachePath);
87}
88
Logan033f46e2011-01-06 05:51:24 +080089bool getBooleanProp(const char *str) {
90 char buf[PROPERTY_VALUE_MAX];
91 property_get(str, buf, "0");
92 return strcmp(buf, "0") != 0;
93}
94
Loganecf4cbd2011-01-06 05:34:11 +080095} // namespace anonymous
96
Logancf3e5212010-12-29 01:44:55 +080097namespace bcc {
98
99Script::~Script() {
100 if (mStatus == ScriptStatus::Compiled) {
101 delete mCompiled;
102 }
103}
104
105
106int Script::readBC(const char *bitcode,
107 size_t bitcodeSize,
Logancf3e5212010-12-29 01:44:55 +0800108 const BCCchar *resName,
109 const BCCchar *cacheDir) {
Loganecf4cbd2011-01-06 05:34:11 +0800110 if (mStatus != ScriptStatus::Unknown) {
Logancf3e5212010-12-29 01:44:55 +0800111 mErrorCode = BCC_INVALID_OPERATION;
Loganecf4cbd2011-01-06 05:34:11 +0800112 LOGE("Invalid operation: %s\n", __func__);
Logancf3e5212010-12-29 01:44:55 +0800113 return 1;
114 }
115
Loganecf4cbd2011-01-06 05:34:11 +0800116 sourceBC = bitcode;
117 sourceResName = resName;
118 sourceSize = bitcodeSize;
119
Logan033f46e2011-01-06 05:51:24 +0800120 if (cacheDir && resName) {
121 cacheFile = genCacheFileName(cacheDir, resName, ".oBCC");
122 }
123
Loganecf4cbd2011-01-06 05:34:11 +0800124 return 0;
Logancf3e5212010-12-29 01:44:55 +0800125}
126
127
128int Script::readModule(llvm::Module *module) {
129 if (mStatus != ScriptStatus::Unknown) {
130 mErrorCode = BCC_INVALID_OPERATION;
Loganecf4cbd2011-01-06 05:34:11 +0800131 LOGE("Invalid operation: %s\n", __func__);
Logancf3e5212010-12-29 01:44:55 +0800132 return 1;
133 }
134
Loganecf4cbd2011-01-06 05:34:11 +0800135 sourceModule = module;
136 return 0;
Logancf3e5212010-12-29 01:44:55 +0800137}
138
139
140int Script::linkBC(const char *bitcode, size_t bitcodeSize) {
141 if (mStatus != ScriptStatus::Compiled) {
142 mErrorCode = BCC_INVALID_OPERATION;
143 return 1;
144 }
145
146 return mCompiled->linkBC(bitcode, bitcodeSize);
147}
148
149
Logancf3e5212010-12-29 01:44:55 +0800150int Script::compile() {
Loganecf4cbd2011-01-06 05:34:11 +0800151 if (mStatus != ScriptStatus::Unknown) {
Logancf3e5212010-12-29 01:44:55 +0800152 mErrorCode = BCC_INVALID_OPERATION;
Loganecf4cbd2011-01-06 05:34:11 +0800153 LOGE("Invalid operation: %s\n", __func__);
Logancf3e5212010-12-29 01:44:55 +0800154 return 1;
155 }
156
Loganecf4cbd2011-01-06 05:34:11 +0800157 // Load Cache File
Logan033f46e2011-01-06 05:51:24 +0800158 if (cacheFile && internalLoadCache() == 0) {
159 return 0;
160 }
Loganecf4cbd2011-01-06 05:34:11 +0800161
Logan033f46e2011-01-06 05:51:24 +0800162 return internalCompile();
163}
164
165
166int Script::internalLoadCache() {
167 if (getBooleanProp("debug.bcc.nocache")) {
168 // Android system environment property disable the cache mechanism by
169 // setting "debug.bcc.nocache". So we will not load the cache file any
170 // way.
171 return 1;
172 }
173
174#if 0
175 if (resName && !mCacheLoadFailed) {
176 mUseCache = true;
177
178 mCacheFd = openCacheFile(resName, cacheDir, true /* createIfMissing */);
179 if (mCacheFd >= 0 && !mCacheNew) { // Just use cache file
180 return -mCacheFd - 1;
181 }
182 }
183#endif
184 // TODO(logan): Implement this.
185
186 return 1;
187}
188
189
190int Script::internalCompile() {
191 // Create the ScriptCompiled object
Loganecf4cbd2011-01-06 05:34:11 +0800192 mCompiled = new (nothrow) ScriptCompiled(this);
193
194 if (!mCompiled) {
195 mErrorCode = BCC_OUT_OF_MEMORY;
196 LOGE("Out of memory: %s %d\n", __FILE__, __LINE__);
197 return 1;
198 }
199
200 mStatus = ScriptStatus::Compiled;
201
Logan033f46e2011-01-06 05:51:24 +0800202 // Register symbol lookup function
Loganecf4cbd2011-01-06 05:34:11 +0800203 if (mpExtSymbolLookupFn) {
204 mCompiled->registerSymbolCallback(mpExtSymbolLookupFn,
205 mpExtSymbolLookupFnContext);
206 }
207
Logan033f46e2011-01-06 05:51:24 +0800208 // Setup the source bitcode / module
Loganecf4cbd2011-01-06 05:34:11 +0800209 if (sourceBC) {
Loganf30a6712011-01-06 05:55:34 +0800210 if (mCompiled->readBC(sourceBC, sourceSize, sourceResName, 0) != 0) {
Logan033f46e2011-01-06 05:51:24 +0800211 return 1;
Loganecf4cbd2011-01-06 05:34:11 +0800212 }
213 } else if (sourceModule) {
Logan033f46e2011-01-06 05:51:24 +0800214 if (mCompiled->readModule(sourceModule) != 0) {
215 return 1;
Loganecf4cbd2011-01-06 05:34:11 +0800216 }
217 }
218
Logan033f46e2011-01-06 05:51:24 +0800219 // TODO(logan): Link source with the library
220 //if (libraryBC) {
221 // if (mCompiled->linkBC(libraryBC, librarySize) != 0) {
222 // return 1;
223 // }
224 //}
Loganecf4cbd2011-01-06 05:34:11 +0800225
Logancf3e5212010-12-29 01:44:55 +0800226 return mCompiled->compile();
227}
228
229
230char const *Script::getCompilerErrorMessage() {
231 if (mStatus != ScriptStatus::Compiled) {
232 mErrorCode = BCC_INVALID_OPERATION;
233 return NULL;
234 }
235
236 return mCompiled->getCompilerErrorMessage();
237}
238
239
240void *Script::lookup(const char *name) {
241 if (mStatus != ScriptStatus::Compiled) {
242 mErrorCode = BCC_INVALID_OPERATION;
243 return NULL;
244 }
245
246 return mCompiled->lookup(name);
247}
248
249
250void Script::getExportVars(BCCsizei *actualVarCount,
251 BCCsizei maxVarCount,
252 BCCvoid **vars) {
253 if (mStatus != ScriptStatus::Compiled) {
254 mErrorCode = BCC_INVALID_OPERATION;
255 return;
256 }
257
258 mCompiled->getExportVars(actualVarCount, maxVarCount, vars);
259}
260
261
262void Script::getExportFuncs(BCCsizei *actualFuncCount,
263 BCCsizei maxFuncCount,
264 BCCvoid **funcs) {
265 if (mStatus != ScriptStatus::Compiled) {
266 mErrorCode = BCC_INVALID_OPERATION;
267 return;
268 }
269
270 mCompiled->getExportFuncs(actualFuncCount, maxFuncCount, funcs);
271}
272
273
274void Script::getPragmas(BCCsizei *actualStringCount,
275 BCCsizei maxStringCount,
276 BCCchar **strings) {
277 if (mStatus != ScriptStatus::Compiled) {
278 mErrorCode = BCC_INVALID_OPERATION;
279 return;
280 }
281
282 mCompiled->getPragmas(actualStringCount, maxStringCount, strings);
283}
284
285
286void Script::getFunctions(BCCsizei *actualFunctionCount,
287 BCCsizei maxFunctionCount,
288 BCCchar **functions) {
289 if (mStatus != ScriptStatus::Compiled) {
290 mErrorCode = BCC_INVALID_OPERATION;
291 return;
292 }
293
294 mCompiled->getFunctions(actualFunctionCount, maxFunctionCount, functions);
295}
296
297
298void Script::getFunctionBinary(BCCchar *function,
299 BCCvoid **base,
300 BCCsizei *length) {
301 if (mStatus != ScriptStatus::Compiled) {
302 mErrorCode = BCC_INVALID_OPERATION;
303 return;
304 }
305
306 mCompiled->getFunctionBinary(function, base, length);
307}
308
309
310void Script::registerSymbolCallback(BCCSymbolLookupFn pFn, BCCvoid *pContext) {
311 mpExtSymbolLookupFn = pFn;
312 mpExtSymbolLookupFnContext = pContext;
313
314 if (mStatus != ScriptStatus::Compiled) {
315 mErrorCode = BCC_INVALID_OPERATION;
316 return;
317 }
318
319 mCompiled->registerSymbolCallback(pFn, pContext);
320}
321
322} // namespace bcc