blob: e7cc628a5ac178113536f9b46f8da55ab4164faa [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
Loganecf4cbd2011-01-06 05:34:11 +080026namespace {
27
28// Input: cacheDir
29// Input: resName
30// Input: extName
31//
32// Note: cacheFile = resName + extName
33//
34// Output: Returns cachePath == cacheDir + cacheFile
35char *genCacheFileName(const char *cacheDir,
36 const char *resName,
37 const char *extName) {
38 char cachePath[512];
39 char cacheFile[sizeof(cachePath)];
40 const size_t kBufLen = sizeof(cachePath) - 1;
41
42 cacheFile[0] = '\0';
43 // Note: resName today is usually something like
44 // "/com.android.fountain:raw/fountain"
45 if (resName[0] != '/') {
46 // Get the absolute path of the raw/***.bc file.
47
48 // Generate the absolute path. This doesn't do everything it
49 // should, e.g. if resName is "./out/whatever" it doesn't crunch
50 // the leading "./" out because this if-block is not triggered,
51 // but it'll make do.
52 //
53 if (getcwd(cacheFile, kBufLen) == NULL) {
54 LOGE("Can't get CWD while opening raw/***.bc file\n");
55 return NULL;
56 }
57 // Append "/" at the end of cacheFile so far.
58 strncat(cacheFile, "/", kBufLen);
59 }
60
61 // cacheFile = resName + extName
62 //
63 strncat(cacheFile, resName, kBufLen);
64 if (extName != NULL) {
65 // TODO(srhines): strncat() is a bit dangerous
66 strncat(cacheFile, extName, kBufLen);
67 }
68
69 // Turn the path into a flat filename by replacing
70 // any slashes after the first one with '@' characters.
71 char *cp = cacheFile + 1;
72 while (*cp != '\0') {
73 if (*cp == '/') {
74 *cp = '@';
75 }
76 cp++;
77 }
78
79 // Tack on the file name for the actual cache file path.
80 strncpy(cachePath, cacheDir, kBufLen);
81 strncat(cachePath, cacheFile, kBufLen);
82
83 LOGV("Cache file for '%s' '%s' is '%s'\n", resName, extName, cachePath);
84 return strdup(cachePath);
85}
86
87} // namespace anonymous
88
Logancf3e5212010-12-29 01:44:55 +080089namespace bcc {
90
91Script::~Script() {
92 if (mStatus == ScriptStatus::Compiled) {
93 delete mCompiled;
94 }
95}
96
97
98int Script::readBC(const char *bitcode,
99 size_t bitcodeSize,
100 long bitcodeFileModTime,
101 long bitcodeFileCRC32,
102 const BCCchar *resName,
103 const BCCchar *cacheDir) {
Loganecf4cbd2011-01-06 05:34:11 +0800104 if (mStatus != ScriptStatus::Unknown) {
Logancf3e5212010-12-29 01:44:55 +0800105 mErrorCode = BCC_INVALID_OPERATION;
Loganecf4cbd2011-01-06 05:34:11 +0800106 LOGE("Invalid operation: %s\n", __func__);
Logancf3e5212010-12-29 01:44:55 +0800107 return 1;
108 }
109
Loganecf4cbd2011-01-06 05:34:11 +0800110 cacheFile = genCacheFileName(cacheDir, resName, ".oBCC");
Logancf3e5212010-12-29 01:44:55 +0800111
Loganecf4cbd2011-01-06 05:34:11 +0800112 sourceBC = bitcode;
113 sourceResName = resName;
114 sourceSize = bitcodeSize;
115
116 return 0;
Logancf3e5212010-12-29 01:44:55 +0800117}
118
119
120int Script::readModule(llvm::Module *module) {
121 if (mStatus != ScriptStatus::Unknown) {
122 mErrorCode = BCC_INVALID_OPERATION;
Loganecf4cbd2011-01-06 05:34:11 +0800123 LOGE("Invalid operation: %s\n", __func__);
Logancf3e5212010-12-29 01:44:55 +0800124 return 1;
125 }
126
Loganecf4cbd2011-01-06 05:34:11 +0800127 sourceModule = module;
128 return 0;
Logancf3e5212010-12-29 01:44:55 +0800129}
130
131
132int Script::linkBC(const char *bitcode, size_t bitcodeSize) {
133 if (mStatus != ScriptStatus::Compiled) {
134 mErrorCode = BCC_INVALID_OPERATION;
135 return 1;
136 }
137
138 return mCompiled->linkBC(bitcode, bitcodeSize);
139}
140
141
Logancf3e5212010-12-29 01:44:55 +0800142int Script::compile() {
Loganecf4cbd2011-01-06 05:34:11 +0800143 if (mStatus != ScriptStatus::Unknown) {
Logancf3e5212010-12-29 01:44:55 +0800144 mErrorCode = BCC_INVALID_OPERATION;
Loganecf4cbd2011-01-06 05:34:11 +0800145 LOGE("Invalid operation: %s\n", __func__);
Logancf3e5212010-12-29 01:44:55 +0800146 return 1;
147 }
148
Loganecf4cbd2011-01-06 05:34:11 +0800149 // Load Cache File
150 // TODO(logan): Complete this.
151
152 // Compile
153 mCompiled = new (nothrow) ScriptCompiled(this);
154
155 if (!mCompiled) {
156 mErrorCode = BCC_OUT_OF_MEMORY;
157 LOGE("Out of memory: %s %d\n", __FILE__, __LINE__);
158 return 1;
159 }
160
161 mStatus = ScriptStatus::Compiled;
162
163 if (mpExtSymbolLookupFn) {
164 mCompiled->registerSymbolCallback(mpExtSymbolLookupFn,
165 mpExtSymbolLookupFnContext);
166 }
167
168 if (sourceBC) {
169 int ret = mCompiled->readBC(sourceBC, sourceSize, 0, 0, sourceResName, 0);
170 if (ret != 0) {
171 return ret;
172 }
173 } else if (sourceModule) {
174 int ret = mCompiled->readModule(sourceModule);
175 if (ret != 0) {
176 return ret;
177 }
178 }
179
180 // TODO(logan): Link
181
Logancf3e5212010-12-29 01:44:55 +0800182 return mCompiled->compile();
183}
184
185
186char const *Script::getCompilerErrorMessage() {
187 if (mStatus != ScriptStatus::Compiled) {
188 mErrorCode = BCC_INVALID_OPERATION;
189 return NULL;
190 }
191
192 return mCompiled->getCompilerErrorMessage();
193}
194
195
196void *Script::lookup(const char *name) {
197 if (mStatus != ScriptStatus::Compiled) {
198 mErrorCode = BCC_INVALID_OPERATION;
199 return NULL;
200 }
201
202 return mCompiled->lookup(name);
203}
204
205
206void Script::getExportVars(BCCsizei *actualVarCount,
207 BCCsizei maxVarCount,
208 BCCvoid **vars) {
209 if (mStatus != ScriptStatus::Compiled) {
210 mErrorCode = BCC_INVALID_OPERATION;
211 return;
212 }
213
214 mCompiled->getExportVars(actualVarCount, maxVarCount, vars);
215}
216
217
218void Script::getExportFuncs(BCCsizei *actualFuncCount,
219 BCCsizei maxFuncCount,
220 BCCvoid **funcs) {
221 if (mStatus != ScriptStatus::Compiled) {
222 mErrorCode = BCC_INVALID_OPERATION;
223 return;
224 }
225
226 mCompiled->getExportFuncs(actualFuncCount, maxFuncCount, funcs);
227}
228
229
230void Script::getPragmas(BCCsizei *actualStringCount,
231 BCCsizei maxStringCount,
232 BCCchar **strings) {
233 if (mStatus != ScriptStatus::Compiled) {
234 mErrorCode = BCC_INVALID_OPERATION;
235 return;
236 }
237
238 mCompiled->getPragmas(actualStringCount, maxStringCount, strings);
239}
240
241
242void Script::getFunctions(BCCsizei *actualFunctionCount,
243 BCCsizei maxFunctionCount,
244 BCCchar **functions) {
245 if (mStatus != ScriptStatus::Compiled) {
246 mErrorCode = BCC_INVALID_OPERATION;
247 return;
248 }
249
250 mCompiled->getFunctions(actualFunctionCount, maxFunctionCount, functions);
251}
252
253
254void Script::getFunctionBinary(BCCchar *function,
255 BCCvoid **base,
256 BCCsizei *length) {
257 if (mStatus != ScriptStatus::Compiled) {
258 mErrorCode = BCC_INVALID_OPERATION;
259 return;
260 }
261
262 mCompiled->getFunctionBinary(function, base, length);
263}
264
265
266void Script::registerSymbolCallback(BCCSymbolLookupFn pFn, BCCvoid *pContext) {
267 mpExtSymbolLookupFn = pFn;
268 mpExtSymbolLookupFnContext = pContext;
269
270 if (mStatus != ScriptStatus::Compiled) {
271 mErrorCode = BCC_INVALID_OPERATION;
272 return;
273 }
274
275 mCompiled->registerSymbolCallback(pFn, pContext);
276}
277
278} // namespace bcc