blob: 4b0b406ba4397aca5aa77408b1596a304e8f9107 [file] [log] [blame]
Logancf3e5212010-12-29 01:44:55 +08001/*
Stephen Hinescc366e52012-02-21 17:22:04 -08002 * copyright 2010-2012, the android open source project
Logancf3e5212010-12-29 01:44:55 +08003 *
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
Logancf3e5212010-12-29 01:44:55 +080017#include "Script.h"
18
Logan35849002011-01-15 07:30:43 +080019#include "Config.h"
20
Logan Chiend2a5f302011-07-19 20:32:25 +080021#if USE_OLD_JIT
22#include "OldJIT/CacheReader.h"
23#include "OldJIT/CacheWriter.h"
24#endif
25
Shih-wei Liao5e3e0ce2011-06-17 13:59:46 -070026#include "MCCacheReader.h"
27#include "MCCacheWriter.h"
Zonr Chang2fcbd022012-01-06 21:04:31 +080028#include "CompilerOption.h"
Logan Chiend2a5f302011-07-19 20:32:25 +080029
30#if USE_OLD_JIT
31#include "OldJIT/ContextManager.h"
32#endif
33
Logan4dcd6792011-02-28 05:12:00 +080034#include "DebugHelper.h"
Logan04329712011-01-06 06:10:57 +080035#include "FileHandle.h"
Daniel Malea094881f2011-12-14 17:39:16 -050036#include "GDBJITRegistrar.h"
Logancf3e5212010-12-29 01:44:55 +080037#include "ScriptCompiled.h"
Logan9a5f8682011-01-07 06:09:57 +080038#include "ScriptCached.h"
39#include "Sha1Helper.h"
Logan474cbd22011-01-31 01:47:44 +080040#include "SourceInfo.h"
Logancf3e5212010-12-29 01:44:55 +080041
Logan89eb47f2011-01-07 10:45:16 +080042#include <errno.h>
Logan474cbd22011-01-31 01:47:44 +080043#include <sys/stat.h>
44#include <sys/types.h>
Bhanu Chetlapallieb4509b2012-01-08 20:42:56 -080045#include <unistd.h>
Logancf3e5212010-12-29 01:44:55 +080046
Logan89eb47f2011-01-07 10:45:16 +080047#include <new>
48#include <string.h>
Logan033f46e2011-01-06 05:51:24 +080049#include <cutils/properties.h>
50
Loganecf4cbd2011-01-06 05:34:11 +080051namespace {
52
Logan033f46e2011-01-06 05:51:24 +080053bool getBooleanProp(const char *str) {
Loganf340bf72011-01-14 17:51:40 +080054 char buf[PROPERTY_VALUE_MAX];
55 property_get(str, buf, "0");
56 return strcmp(buf, "0") != 0;
Logan033f46e2011-01-06 05:51:24 +080057}
58
Loganecf4cbd2011-01-06 05:34:11 +080059} // namespace anonymous
60
Logancf3e5212010-12-29 01:44:55 +080061namespace bcc {
62
63Script::~Script() {
Logan35849002011-01-15 07:30:43 +080064 switch (mStatus) {
65 case ScriptStatus::Compiled:
Logancf3e5212010-12-29 01:44:55 +080066 delete mCompiled;
Logan35849002011-01-15 07:30:43 +080067 break;
68
69#if USE_CACHE
70 case ScriptStatus::Cached:
Shih-wei Liaoc4cf6542011-01-13 01:43:01 -080071 delete mCached;
Logan35849002011-01-15 07:30:43 +080072 break;
73#endif
74
75 default:
76 break;
Logancf3e5212010-12-29 01:44:55 +080077 }
Logan474cbd22011-01-31 01:47:44 +080078
Shih-wei Liao6a60f4e2012-01-17 02:58:40 -080079 for (size_t i = 0; i < 2; ++i) {
Logan474cbd22011-01-31 01:47:44 +080080 delete mSourceList[i];
Shih-wei Liao6a60f4e2012-01-17 02:58:40 -080081 }
Logancf3e5212010-12-29 01:44:55 +080082}
83
84
Logan474cbd22011-01-31 01:47:44 +080085int Script::addSourceBC(size_t idx,
86 char const *resName,
87 const char *bitcode,
88 size_t bitcodeSize,
89 unsigned long flags) {
Shih-wei Liao898c5a92011-05-18 07:02:39 -070090
91 if (!resName) {
92 mErrorCode = BCC_INVALID_VALUE;
Steve Block10c14122012-01-08 10:15:06 +000093 ALOGE("Invalid argument: resName = NULL\n");
Shih-wei Liao898c5a92011-05-18 07:02:39 -070094 return 1;
95 }
96
Loganecf4cbd2011-01-06 05:34:11 +080097 if (mStatus != ScriptStatus::Unknown) {
Logancf3e5212010-12-29 01:44:55 +080098 mErrorCode = BCC_INVALID_OPERATION;
Steve Block10c14122012-01-08 10:15:06 +000099 ALOGE("Bad operation: Adding source after bccPrepareExecutable\n");
Logancf3e5212010-12-29 01:44:55 +0800100 return 1;
101 }
102
Logan474cbd22011-01-31 01:47:44 +0800103 if (!bitcode) {
104 mErrorCode = BCC_INVALID_VALUE;
Steve Block10c14122012-01-08 10:15:06 +0000105 ALOGE("Invalid argument: bitcode = NULL\n");
Logan474cbd22011-01-31 01:47:44 +0800106 return 1;
107 }
108
109 mSourceList[idx] = SourceInfo::createFromBuffer(resName,
110 bitcode, bitcodeSize,
111 flags);
112
113 if (!mSourceList[idx]) {
114 mErrorCode = BCC_OUT_OF_MEMORY;
Steve Block10c14122012-01-08 10:15:06 +0000115 ALOGE("Out of memory while adding source bitcode\n");
Logan474cbd22011-01-31 01:47:44 +0800116 return 1;
117 }
118
Loganecf4cbd2011-01-06 05:34:11 +0800119 return 0;
Logancf3e5212010-12-29 01:44:55 +0800120}
121
122
Logan474cbd22011-01-31 01:47:44 +0800123int Script::addSourceModule(size_t idx,
124 llvm::Module *module,
125 unsigned long flags) {
Logancf3e5212010-12-29 01:44:55 +0800126 if (mStatus != ScriptStatus::Unknown) {
127 mErrorCode = BCC_INVALID_OPERATION;
Steve Block10c14122012-01-08 10:15:06 +0000128 ALOGE("Bad operation: Adding source after bccPrepareExecutable\n");
Logancf3e5212010-12-29 01:44:55 +0800129 return 1;
130 }
131
Logan474cbd22011-01-31 01:47:44 +0800132 if (!module) {
133 mErrorCode = BCC_INVALID_VALUE;
Steve Block10c14122012-01-08 10:15:06 +0000134 ALOGE("Invalid argument: module = NULL\n");
Logan474cbd22011-01-31 01:47:44 +0800135 return 1;
136 }
137
138 mSourceList[idx] = SourceInfo::createFromModule(module, flags);
139
140 if (!mSourceList[idx]) {
141 mErrorCode = BCC_OUT_OF_MEMORY;
Steve Block10c14122012-01-08 10:15:06 +0000142 ALOGE("Out of memory when add source module\n");
Logan474cbd22011-01-31 01:47:44 +0800143 return 1;
144 }
145
Loganecf4cbd2011-01-06 05:34:11 +0800146 return 0;
Logancf3e5212010-12-29 01:44:55 +0800147}
148
149
Logan474cbd22011-01-31 01:47:44 +0800150int Script::addSourceFile(size_t idx,
151 char const *path,
152 unsigned long flags) {
Logan3133c412011-01-06 06:15:40 +0800153 if (mStatus != ScriptStatus::Unknown) {
Logancf3e5212010-12-29 01:44:55 +0800154 mErrorCode = BCC_INVALID_OPERATION;
Steve Block10c14122012-01-08 10:15:06 +0000155 ALOGE("Bad operation: Adding source after bccPrepareExecutable\n");
Logancf3e5212010-12-29 01:44:55 +0800156 return 1;
157 }
158
Logan474cbd22011-01-31 01:47:44 +0800159 if (!path) {
160 mErrorCode = BCC_INVALID_VALUE;
Steve Block10c14122012-01-08 10:15:06 +0000161 ALOGE("Invalid argument: path = NULL\n");
Logan474cbd22011-01-31 01:47:44 +0800162 return 1;
163 }
164
165 struct stat sb;
166 if (stat(path, &sb) != 0) {
167 mErrorCode = BCC_INVALID_VALUE;
Steve Block10c14122012-01-08 10:15:06 +0000168 ALOGE("File not found: %s\n", path);
Logan474cbd22011-01-31 01:47:44 +0800169 return 1;
170 }
171
172 mSourceList[idx] = SourceInfo::createFromFile(path, flags);
173
174 if (!mSourceList[idx]) {
175 mErrorCode = BCC_OUT_OF_MEMORY;
Steve Block10c14122012-01-08 10:15:06 +0000176 ALOGE("Out of memory while adding source file\n");
Logan474cbd22011-01-31 01:47:44 +0800177 return 1;
178 }
179
Logan3133c412011-01-06 06:15:40 +0800180 return 0;
Logancf3e5212010-12-29 01:44:55 +0800181}
182
Shih-wei Liaod8ed6a92012-03-03 01:44:29 -0800183int Script::prepareRelocatable(char const *objPath,
Shih-wei Liao6a60f4e2012-01-17 02:58:40 -0800184 llvm::Reloc::Model RelocModel,
185 unsigned long flags) {
Zonr Chang2fcbd022012-01-06 21:04:31 +0800186 CompilerOption option;
Shih-wei Liao8afed382012-01-10 15:57:24 +0800187 option.RelocModelOpt = RelocModel;
Zonr Chang2fcbd022012-01-06 21:04:31 +0800188 option.LoadAfterCompile = false;
Shih-wei Liao8454a3a2012-03-03 01:50:08 -0800189
Zonr Chang2fcbd022012-01-06 21:04:31 +0800190 int status = internalCompile(option);
Joseph Wen34c600a2011-07-25 17:59:17 -0700191 if (status != 0) {
Steve Block10c14122012-01-08 10:15:06 +0000192 ALOGE("LLVM error message: %s\n", getCompilerErrorMessage());
Shih-wei Liaoa0ed34e2012-03-03 01:33:30 -0800193 return status;
194 }
Shih-wei Liaod8ed6a92012-03-03 01:44:29 -0800195
196 FileHandle objFile;
197 if (objFile.open(objPath, OpenMode::Write) < 0) {
198 ALOGE("Failed to open %s for write.\n", objPath);
199 return 1;
Joseph Wen34c600a2011-07-25 17:59:17 -0700200 }
Shih-wei Liaod8ed6a92012-03-03 01:44:29 -0800201
202 if (static_cast<size_t>(objFile.write(getELF(),
203 getELFSize())) != getELFSize()) {
204 objFile.close();
205 ::unlink(objPath);
206 ALOGE("Unable to write ELF to file %s.\n", objPath);
207 return false;
208 }
209
Shih-wei Liao8454a3a2012-03-03 01:50:08 -0800210 mObjectType = ScriptObject::Relocatable;
211
Shih-wei Liaod8ed6a92012-03-03 01:44:29 -0800212 return 0;
Joseph Wen34c600a2011-07-25 17:59:17 -0700213}
214
Logancf3e5212010-12-29 01:44:55 +0800215
Shih-wei Liao69341742012-03-03 01:45:36 -0800216int Script::prepareSharedObject(char const *objPath,
Shih-wei Liaoa471ebb2012-02-05 00:49:58 -0800217 char const *dsoPath,
218 unsigned long flags) {
219 // TODO: Support cached shared object.
220 return 1;
221}
222
223
Logan Chien311c26f2011-07-11 14:30:34 +0800224int Script::prepareExecutable(char const *cacheDir,
225 char const *cacheName,
226 unsigned long flags) {
Loganecf4cbd2011-01-06 05:34:11 +0800227 if (mStatus != ScriptStatus::Unknown) {
Logancf3e5212010-12-29 01:44:55 +0800228 mErrorCode = BCC_INVALID_OPERATION;
Steve Block10c14122012-01-08 10:15:06 +0000229 ALOGE("Invalid operation: %s\n", __func__);
Logancf3e5212010-12-29 01:44:55 +0800230 return 1;
231 }
232
Daniel Malea094881f2011-12-14 17:39:16 -0500233 int status = -1;
Logan35849002011-01-15 07:30:43 +0800234#if USE_CACHE
Shih-wei Liao8454a3a2012-03-03 01:50:08 -0800235 status = internalLoadCache(cacheDir, cacheName, /* checkOnly */ false);
Logan35849002011-01-15 07:30:43 +0800236#endif
Loganecf4cbd2011-01-06 05:34:11 +0800237
Stephen Hinese0918ac2012-03-01 23:28:09 -0800238 if (status != 0) {
239 CompilerOption option;
240 status = internalCompile(option);
Stephen Hinese0918ac2012-03-01 23:28:09 -0800241
Shih-wei Liaoa0ed34e2012-03-03 01:33:30 -0800242 if (status != 0) {
243 ALOGE("LLVM error message: %s\n", getCompilerErrorMessage());
244 return status;
245 }
246
247 status = writeCache();
248 if (status != 0) {
249 ALOGE("Failed to write the cache for %s\n", cacheName);
250 return status;
251 }
Stephen Hines27b35102011-05-11 17:58:48 -0700252 }
Daniel Malea094881f2011-12-14 17:39:16 -0500253
254 // FIXME: Registration can be conditional on the presence of debug metadata
Shih-wei Liaoa0ed34e2012-03-03 01:33:30 -0800255 registerObjectWithGDB(getELF(), getELFSize()); // thread-safe registration
256
Shih-wei Liao8454a3a2012-03-03 01:50:08 -0800257 mObjectType = ScriptObject::Executable;
258
Stephen Hines27b35102011-05-11 17:58:48 -0700259 return status;
Logan033f46e2011-01-06 05:51:24 +0800260}
261
Logan35849002011-01-15 07:30:43 +0800262#if USE_CACHE
Zonr Chang743dd712012-01-19 10:13:52 +0800263int Script::internalLoadCache(char const *cacheDir, char const *cacheName,
Zonr Chang743dd712012-01-19 10:13:52 +0800264 bool checkOnly) {
Shih-wei Liao32ef88b2012-02-04 23:33:11 -0800265 if ((cacheDir == NULL) || (cacheName == NULL)) {
Zonr Chang743dd712012-01-19 10:13:52 +0800266 return 1;
Shih-wei Liao32ef88b2012-02-04 23:33:11 -0800267 }
Zonr Chang743dd712012-01-19 10:13:52 +0800268
269 // Set cache file Name
270 mCacheName = cacheName;
271
Shih-wei Liao32ef88b2012-02-04 23:33:11 -0800272 // Santize mCacheDir. Ensure that mCacheDir ends with '/'.
Zonr Chang743dd712012-01-19 10:13:52 +0800273 mCacheDir = cacheDir;
Shih-wei Liao32ef88b2012-02-04 23:33:11 -0800274 if (!mCacheDir.empty() && *mCacheDir.rbegin() != '/') {
Zonr Chang743dd712012-01-19 10:13:52 +0800275 mCacheDir.push_back('/');
Shih-wei Liao32ef88b2012-02-04 23:33:11 -0800276 }
Zonr Chang743dd712012-01-19 10:13:52 +0800277
Shih-wei Liao32ef88b2012-02-04 23:33:11 -0800278 if (!isCacheable()) {
Logan033f46e2011-01-06 05:51:24 +0800279 return 1;
Shih-wei Liao32ef88b2012-02-04 23:33:11 -0800280 }
Logan04329712011-01-06 06:10:57 +0800281
Zonr Chang4ea08862012-01-17 17:26:49 +0800282 std::string objPath = getCachedObjectPath();
283 std::string infoPath = getCacheInfoPath();
Shih-wei Liao5e3e0ce2011-06-17 13:59:46 -0700284
Logan Chien311c26f2011-07-11 14:30:34 +0800285 FileHandle objFile;
Shih-wei Liao5e3e0ce2011-06-17 13:59:46 -0700286 if (objFile.open(objPath.c_str(), OpenMode::Read) < 0) {
Logan Chien03a2e302011-07-13 21:46:32 +0800287 // Unable to open the executable file in read mode.
Logan04329712011-01-06 06:10:57 +0800288 return 1;
289 }
290
Logan Chien311c26f2011-07-11 14:30:34 +0800291 FileHandle infoFile;
Shih-wei Liao5e3e0ce2011-06-17 13:59:46 -0700292 if (infoFile.open(infoPath.c_str(), OpenMode::Read) < 0) {
Logan Chien03a2e302011-07-13 21:46:32 +0800293 // Unable to open the metadata information file in read mode.
Shih-wei Liao5e3e0ce2011-06-17 13:59:46 -0700294 return 1;
295 }
296
Logan Chien311c26f2011-07-11 14:30:34 +0800297#if USE_OLD_JIT
298 CacheReader reader;
299#elif USE_MCJIT
Shih-wei Liao5e3e0ce2011-06-17 13:59:46 -0700300 MCCacheReader reader;
301
302 // Register symbol lookup function
303 if (mpExtSymbolLookupFn) {
304 reader.registerSymbolCallback(mpExtSymbolLookupFn,
305 mpExtSymbolLookupFnContext);
306 }
Shih-wei Liaob65410d2011-06-19 11:11:48 -0700307#endif
Logan04329712011-01-06 06:10:57 +0800308
Logan9a5f8682011-01-07 06:09:57 +0800309 // Dependencies
Joseph Wen2ca6e572011-06-24 14:12:23 -0700310 reader.addDependency(BCC_FILE_RESOURCE, pathLibBCC_SHA1, sha1LibBCC_SHA1);
Joseph Wen76919072011-07-07 23:06:15 -0700311 reader.addDependency(BCC_FILE_RESOURCE, pathLibRS, sha1LibRS);
Logan9a5f8682011-01-07 06:09:57 +0800312
Logan474cbd22011-01-31 01:47:44 +0800313 for (size_t i = 0; i < 2; ++i) {
314 if (mSourceList[i]) {
315 mSourceList[i]->introDependency(reader);
316 }
Logan9a5f8682011-01-07 06:09:57 +0800317 }
318
Joseph Wen34c600a2011-07-25 17:59:17 -0700319 if (checkOnly)
Joseph Wen49281042011-07-26 10:04:09 -0700320 return !reader.checkCacheFile(&objFile, &infoFile, this);
Joseph Wen34c600a2011-07-25 17:59:17 -0700321
Logan9a5f8682011-01-07 06:09:57 +0800322 // Read cache file
Shih-wei Liao5e3e0ce2011-06-17 13:59:46 -0700323 ScriptCached *cached = reader.readCacheFile(&objFile, &infoFile, this);
Shih-wei Liaob65410d2011-06-19 11:11:48 -0700324
Logan04329712011-01-06 06:10:57 +0800325 if (!cached) {
Logan42598052011-01-26 22:41:13 +0800326 mIsContextSlotNotAvail = reader.isContextSlotNotAvail();
Logan04329712011-01-06 06:10:57 +0800327 return 1;
328 }
329
330 mCached = cached;
331 mStatus = ScriptStatus::Cached;
Logan033f46e2011-01-06 05:51:24 +0800332
Loganf3c83ce2011-01-07 06:36:33 +0800333 // Dirty hack for libRS.
334 // TODO(all): This dirty hack should be removed in the future.
Shih-wei Liao8eb5fe92011-02-01 04:17:38 -0800335 if (!cached->isLibRSThreadable() && mpExtSymbolLookupFn) {
Loganf3c83ce2011-01-07 06:36:33 +0800336 mpExtSymbolLookupFn(mpExtSymbolLookupFnContext, "__clearThreadable");
337 }
338
Loganf7f0ac52011-01-07 03:53:43 +0800339 return 0;
Logan033f46e2011-01-06 05:51:24 +0800340}
Logan35849002011-01-15 07:30:43 +0800341#endif
Logan033f46e2011-01-06 05:51:24 +0800342
Shih-wei Liao9e81e372012-01-17 16:38:40 -0800343int Script::internalCompile(const CompilerOption &option) {
Logan033f46e2011-01-06 05:51:24 +0800344 // Create the ScriptCompiled object
Nowar Gu09b6c1c2011-05-24 23:49:07 +0800345 mCompiled = new (std::nothrow) ScriptCompiled(this);
Loganecf4cbd2011-01-06 05:34:11 +0800346
347 if (!mCompiled) {
348 mErrorCode = BCC_OUT_OF_MEMORY;
Steve Block10c14122012-01-08 10:15:06 +0000349 ALOGE("Out of memory: %s %d\n", __FILE__, __LINE__);
Loganecf4cbd2011-01-06 05:34:11 +0800350 return 1;
351 }
352
353 mStatus = ScriptStatus::Compiled;
354
Logan033f46e2011-01-06 05:51:24 +0800355 // Register symbol lookup function
Loganecf4cbd2011-01-06 05:34:11 +0800356 if (mpExtSymbolLookupFn) {
357 mCompiled->registerSymbolCallback(mpExtSymbolLookupFn,
358 mpExtSymbolLookupFnContext);
359 }
360
Zonr Changdf3fee42012-01-10 15:58:36 +0800361 if (!mSourceList[0]) {
362 ALOGE("Source bitcode is not set.\n");
Logan474cbd22011-01-31 01:47:44 +0800363 return 1;
364 }
365
Shih-wei Liaod88c0d12012-01-17 20:32:58 -0800366 // Parse Source bitcode file (if necessary)
367 if (mSourceList[0]->prepareModule() != 0) {
368 ALOGE("Unable to setup source module\n");
Zonr Changdf3fee42012-01-10 15:58:36 +0800369 return 1;
Shih-wei Liaod88c0d12012-01-17 20:32:58 -0800370 }
371
372 // Parse Library bitcode file (if necessary)
373 if (mSourceList[1]) {
374 if (mSourceList[1]->prepareModule(mSourceList[0]->getContext()) != 0) {
375 ALOGE("Unable to setup library module\n");
376 return 1;
377 }
378 }
Zonr Changdf3fee42012-01-10 15:58:36 +0800379
380 // Set the main source module
381 if (mCompiled->readModule(mSourceList[0]->getModule()) != 0) {
Steve Block10c14122012-01-08 10:15:06 +0000382 ALOGE("Unable to read source module\n");
Logan474cbd22011-01-31 01:47:44 +0800383 return 1;
Loganecf4cbd2011-01-06 05:34:11 +0800384 }
385
Logan3133c412011-01-06 06:15:40 +0800386 // Link the source module with the library module
Shih-wei Liaod88c0d12012-01-17 20:32:58 -0800387 if (mSourceList[1]) {
Zonr Changdf3fee42012-01-10 15:58:36 +0800388 if (mCompiled->linkModule(mSourceList[1]->getModule()) != 0) {
Steve Block10c14122012-01-08 10:15:06 +0000389 ALOGE("Unable to link library module\n");
Logan04329712011-01-06 06:10:57 +0800390 return 1;
391 }
392 }
Loganecf4cbd2011-01-06 05:34:11 +0800393
Logan3133c412011-01-06 06:15:40 +0800394 // Compile and JIT the code
Zonr Chang2fcbd022012-01-06 21:04:31 +0800395 if (mCompiled->compile(option) != 0) {
Steve Block10c14122012-01-08 10:15:06 +0000396 ALOGE("Unable to compile.\n");
Logan04329712011-01-06 06:10:57 +0800397 return 1;
398 }
399
Shih-wei Liaoa0ed34e2012-03-03 01:33:30 -0800400 return 0;
401}
402
403int Script::writeCache() {
Stephen Hines3e36c692012-03-05 12:39:45 -0800404 // Not compiled script or encountered error during the compilation.
Shih-wei Liaoa0ed34e2012-03-03 01:33:30 -0800405 if ((mStatus != ScriptStatus::Compiled) ||
406 (getCompilerErrorMessage() == NULL))
407 return 1;
408
Logan35849002011-01-15 07:30:43 +0800409#if USE_CACHE
Logan42598052011-01-26 22:41:13 +0800410 // Note: If we re-compile the script because the cached context slot not
411 // available, then we don't have to write the cache.
412
413 // Note: If the address of the context is not in the context slot, then
414 // we don't have to cache it.
415
Shih-wei Liaoabc7f512012-01-18 00:34:07 -0800416 if (
Shih-wei Liao5e3e0ce2011-06-17 13:59:46 -0700417#if USE_OLD_JIT
Logan1dc63142011-02-25 17:14:51 +0800418 !mIsContextSlotNotAvail &&
419 ContextManager::get().isManagingContext(getContext()) &&
Shih-wei Liao5e3e0ce2011-06-17 13:59:46 -0700420#endif
Shih-wei Liaoabc7f512012-01-18 00:34:07 -0800421 isCacheable()) {
Logan42598052011-01-26 22:41:13 +0800422
Zonr Chang4ea08862012-01-17 17:26:49 +0800423 std::string objPath = getCachedObjectPath();
424 std::string infoPath = getCacheInfoPath();
Logan Chien311c26f2011-07-11 14:30:34 +0800425
Jeff Brown937a0bc2011-01-26 23:20:14 -0800426 // Remove the file if it already exists before writing the new file.
427 // The old file may still be mapped elsewhere in memory and we do not want
428 // to modify its contents. (The same script may be running concurrently in
429 // the same process or a different process!)
Shih-wei Liao5e3e0ce2011-06-17 13:59:46 -0700430 ::unlink(objPath.c_str());
Logan Chien311c26f2011-07-11 14:30:34 +0800431#if !USE_OLD_JIT && USE_MCJIT
Shih-wei Liao5e3e0ce2011-06-17 13:59:46 -0700432 ::unlink(infoPath.c_str());
433#endif
Jeff Brown937a0bc2011-01-26 23:20:14 -0800434
Logan Chien03a2e302011-07-13 21:46:32 +0800435 FileHandle objFile;
436 FileHandle infoFile;
437
438 if (objFile.open(objPath.c_str(), OpenMode::Write) >= 0 &&
439 infoFile.open(infoPath.c_str(), OpenMode::Write) >= 0) {
Shih-wei Liaob65410d2011-06-19 11:11:48 -0700440
Shih-wei Liao5e3e0ce2011-06-17 13:59:46 -0700441#if USE_OLD_JIT
Logan04329712011-01-06 06:10:57 +0800442 CacheWriter writer;
Logan Chien311c26f2011-07-11 14:30:34 +0800443#elif USE_MCJIT
444 MCCacheWriter writer;
Shih-wei Liao5e3e0ce2011-06-17 13:59:46 -0700445#endif
Logana27a83f2011-01-07 10:25:48 +0800446
Joseph Wen2ca6e572011-06-24 14:12:23 -0700447#ifdef TARGET_BUILD
Logana2e15af2011-01-07 11:46:08 +0800448 // Dependencies
Joseph Wen2ca6e572011-06-24 14:12:23 -0700449 writer.addDependency(BCC_FILE_RESOURCE, pathLibBCC_SHA1, sha1LibBCC_SHA1);
Joseph Wen76919072011-07-07 23:06:15 -0700450 writer.addDependency(BCC_FILE_RESOURCE, pathLibRS, sha1LibRS);
Logane1323992011-01-12 04:47:13 +0800451#endif
Logana2e15af2011-01-07 11:46:08 +0800452
Logan474cbd22011-01-31 01:47:44 +0800453 for (size_t i = 0; i < 2; ++i) {
Logan825c3b22011-02-28 05:05:48 +0800454 if (mSourceList[i]) {
455 mSourceList[i]->introDependency(writer);
456 }
Logana2e15af2011-01-07 11:46:08 +0800457 }
458
Logana27a83f2011-01-07 10:25:48 +0800459 // libRS is threadable dirty hack
460 // TODO: This should be removed in the future
461 uint32_t libRS_threadable = 0;
462 if (mpExtSymbolLookupFn) {
Logan89eb47f2011-01-07 10:45:16 +0800463 libRS_threadable =
464 (uint32_t)mpExtSymbolLookupFn(mpExtSymbolLookupFnContext,
465 "__isThreadable");
Logana27a83f2011-01-07 10:25:48 +0800466 }
Shih-wei Liaob65410d2011-06-19 11:11:48 -0700467
Shih-wei Liao5e3e0ce2011-06-17 13:59:46 -0700468 if (!writer.writeCacheFile(&objFile, &infoFile, this, libRS_threadable)) {
Shih-wei Liao5e3e0ce2011-06-17 13:59:46 -0700469 objFile.truncate();
470 objFile.close();
Logana27a83f2011-01-07 10:25:48 +0800471
Shih-wei Liao5e3e0ce2011-06-17 13:59:46 -0700472 if (unlink(objPath.c_str()) != 0) {
Steve Block10c14122012-01-08 10:15:06 +0000473 ALOGE("Unable to remove the invalid cache file: %s. (reason: %s)\n",
Shih-wei Liao5e3e0ce2011-06-17 13:59:46 -0700474 objPath.c_str(), strerror(errno));
Logan89eb47f2011-01-07 10:45:16 +0800475 }
Shih-wei Liao5e3e0ce2011-06-17 13:59:46 -0700476
Shih-wei Liao5e3e0ce2011-06-17 13:59:46 -0700477 infoFile.truncate();
478 infoFile.close();
479
480 if (unlink(infoPath.c_str()) != 0) {
Steve Block10c14122012-01-08 10:15:06 +0000481 ALOGE("Unable to remove the invalid cache file: %s. (reason: %s)\n",
Shih-wei Liao5e3e0ce2011-06-17 13:59:46 -0700482 infoPath.c_str(), strerror(errno));
483 }
Logan89eb47f2011-01-07 10:45:16 +0800484 }
485 }
Logan04329712011-01-06 06:10:57 +0800486 }
Logan35849002011-01-15 07:30:43 +0800487#endif // USE_CACHE
Logan04329712011-01-06 06:10:57 +0800488
489 return 0;
Logancf3e5212010-12-29 01:44:55 +0800490}
491
492
493char const *Script::getCompilerErrorMessage() {
494 if (mStatus != ScriptStatus::Compiled) {
495 mErrorCode = BCC_INVALID_OPERATION;
496 return NULL;
497 }
498
499 return mCompiled->getCompilerErrorMessage();
500}
501
502
503void *Script::lookup(const char *name) {
Logan89eb47f2011-01-07 10:45:16 +0800504 switch (mStatus) {
Shih-wei Liaod50be322011-07-01 22:53:31 -0700505 case ScriptStatus::Compiled: {
506 return mCompiled->lookup(name);
507 }
Shih-wei Liaob65410d2011-06-19 11:11:48 -0700508
Logan35849002011-01-15 07:30:43 +0800509#if USE_CACHE
Shih-wei Liaod50be322011-07-01 22:53:31 -0700510 case ScriptStatus::Cached: {
511 return mCached->lookup(name);
512 }
Logan35849002011-01-15 07:30:43 +0800513#endif
Logan89eb47f2011-01-07 10:45:16 +0800514
Shih-wei Liaod50be322011-07-01 22:53:31 -0700515 default: {
516 mErrorCode = BCC_INVALID_OPERATION;
517 return NULL;
518 }
Logancf3e5212010-12-29 01:44:55 +0800519 }
Logancf3e5212010-12-29 01:44:55 +0800520}
521
522
Loganbe79ada2011-01-13 01:33:45 +0800523size_t Script::getExportVarCount() const {
Logan89eb47f2011-01-07 10:45:16 +0800524 switch (mStatus) {
Shih-wei Liaod50be322011-07-01 22:53:31 -0700525 case ScriptStatus::Compiled: {
526 return mCompiled->getExportVarCount();
527 }
Shih-wei Liaob65410d2011-06-19 11:11:48 -0700528
Logan35849002011-01-15 07:30:43 +0800529#if USE_CACHE
Shih-wei Liaod50be322011-07-01 22:53:31 -0700530 case ScriptStatus::Cached: {
531 return mCached->getExportVarCount();
532 }
Logan35849002011-01-15 07:30:43 +0800533#endif
Shih-wei Liaob65410d2011-06-19 11:11:48 -0700534
Shih-wei Liaod50be322011-07-01 22:53:31 -0700535 default: {
536 return 0;
537 }
Loganbe79ada2011-01-13 01:33:45 +0800538 }
539}
540
541
542size_t Script::getExportFuncCount() const {
543 switch (mStatus) {
Shih-wei Liaod50be322011-07-01 22:53:31 -0700544 case ScriptStatus::Compiled: {
545 return mCompiled->getExportFuncCount();
546 }
Shih-wei Liaob65410d2011-06-19 11:11:48 -0700547
Logan35849002011-01-15 07:30:43 +0800548#if USE_CACHE
Shih-wei Liaod50be322011-07-01 22:53:31 -0700549 case ScriptStatus::Cached: {
550 return mCached->getExportFuncCount();
551 }
Logan35849002011-01-15 07:30:43 +0800552#endif
Shih-wei Liaob65410d2011-06-19 11:11:48 -0700553
Shih-wei Liaod50be322011-07-01 22:53:31 -0700554 default: {
555 return 0;
556 }
Loganbe79ada2011-01-13 01:33:45 +0800557 }
558}
559
560
Stephen Hinescc366e52012-02-21 17:22:04 -0800561size_t Script::getExportForEachCount() const {
562 switch (mStatus) {
563 case ScriptStatus::Compiled: {
564 return mCompiled->getExportForEachCount();
565 }
566
567#if USE_CACHE
568 case ScriptStatus::Cached: {
569 return mCached->getExportForEachCount();
570 }
571#endif
572
573 default: {
574 return 0;
575 }
576 }
577}
578
579
Loganbe79ada2011-01-13 01:33:45 +0800580size_t Script::getPragmaCount() const {
581 switch (mStatus) {
Shih-wei Liaod50be322011-07-01 22:53:31 -0700582 case ScriptStatus::Compiled: {
583 return mCompiled->getPragmaCount();
584 }
Shih-wei Liaob65410d2011-06-19 11:11:48 -0700585
Logan35849002011-01-15 07:30:43 +0800586#if USE_CACHE
Shih-wei Liaod50be322011-07-01 22:53:31 -0700587 case ScriptStatus::Cached: {
588 return mCached->getPragmaCount();
589 }
Logan35849002011-01-15 07:30:43 +0800590#endif
Shih-wei Liaob65410d2011-06-19 11:11:48 -0700591
Shih-wei Liaod50be322011-07-01 22:53:31 -0700592 default: {
593 return 0;
594 }
Loganbe79ada2011-01-13 01:33:45 +0800595 }
596}
597
598
599size_t Script::getFuncCount() const {
600 switch (mStatus) {
Shih-wei Liaod50be322011-07-01 22:53:31 -0700601 case ScriptStatus::Compiled: {
602 return mCompiled->getFuncCount();
603 }
Shih-wei Liaob65410d2011-06-19 11:11:48 -0700604
Logan35849002011-01-15 07:30:43 +0800605#if USE_CACHE
Shih-wei Liaod50be322011-07-01 22:53:31 -0700606 case ScriptStatus::Cached: {
607 return mCached->getFuncCount();
608 }
Logan35849002011-01-15 07:30:43 +0800609#endif
Shih-wei Liaob65410d2011-06-19 11:11:48 -0700610
Shih-wei Liaod50be322011-07-01 22:53:31 -0700611 default: {
612 return 0;
613 }
Loganbe79ada2011-01-13 01:33:45 +0800614 }
615}
616
617
Stephen Hines071288a2011-01-27 14:38:26 -0800618size_t Script::getObjectSlotCount() const {
619 switch (mStatus) {
Shih-wei Liaod50be322011-07-01 22:53:31 -0700620 case ScriptStatus::Compiled: {
621 return mCompiled->getObjectSlotCount();
622 }
Shih-wei Liaob65410d2011-06-19 11:11:48 -0700623
Stephen Hines071288a2011-01-27 14:38:26 -0800624#if USE_CACHE
Shih-wei Liaod50be322011-07-01 22:53:31 -0700625 case ScriptStatus::Cached: {
626 return mCached->getObjectSlotCount();
627 }
Stephen Hines071288a2011-01-27 14:38:26 -0800628#endif
Shih-wei Liaob65410d2011-06-19 11:11:48 -0700629
Shih-wei Liaod50be322011-07-01 22:53:31 -0700630 default: {
631 return 0;
632 }
Stephen Hines071288a2011-01-27 14:38:26 -0800633 }
634}
635
636
Loganbe79ada2011-01-13 01:33:45 +0800637void Script::getExportVarList(size_t varListSize, void **varList) {
638 switch (mStatus) {
639#define DELEGATE(STATUS) \
Shih-wei Liaod50be322011-07-01 22:53:31 -0700640 case ScriptStatus::STATUS: \
641 m##STATUS->getExportVarList(varListSize, varList); \
642 break;
Logancf3e5212010-12-29 01:44:55 +0800643
Logan35849002011-01-15 07:30:43 +0800644#if USE_CACHE
Shih-wei Liaod50be322011-07-01 22:53:31 -0700645 DELEGATE(Cached);
Logan35849002011-01-15 07:30:43 +0800646#endif
647
Shih-wei Liaod50be322011-07-01 22:53:31 -0700648 DELEGATE(Compiled);
Loganbe79ada2011-01-13 01:33:45 +0800649#undef DELEGATE
Logan89eb47f2011-01-07 10:45:16 +0800650
Shih-wei Liaod50be322011-07-01 22:53:31 -0700651 default: {
652 mErrorCode = BCC_INVALID_OPERATION;
653 }
Logan89eb47f2011-01-07 10:45:16 +0800654 }
Logancf3e5212010-12-29 01:44:55 +0800655}
656
Joseph Wenf36637f2011-07-06 18:27:12 -0700657void Script::getExportVarNameList(std::vector<std::string> &varList) {
658 switch (mStatus) {
659 case ScriptStatus::Compiled: {
660 return mCompiled->getExportVarNameList(varList);
661 }
662
663 default: {
664 mErrorCode = BCC_INVALID_OPERATION;
665 }
666 }
667}
668
Logancf3e5212010-12-29 01:44:55 +0800669
Loganbe79ada2011-01-13 01:33:45 +0800670void Script::getExportFuncList(size_t funcListSize, void **funcList) {
Logan89eb47f2011-01-07 10:45:16 +0800671 switch (mStatus) {
Loganbe79ada2011-01-13 01:33:45 +0800672#define DELEGATE(STATUS) \
Shih-wei Liaod50be322011-07-01 22:53:31 -0700673 case ScriptStatus::STATUS: \
674 m##STATUS->getExportFuncList(funcListSize, funcList); \
675 break;
Logancf3e5212010-12-29 01:44:55 +0800676
Logan35849002011-01-15 07:30:43 +0800677#if USE_CACHE
Shih-wei Liaod50be322011-07-01 22:53:31 -0700678 DELEGATE(Cached);
Logan35849002011-01-15 07:30:43 +0800679#endif
680
Shih-wei Liaod50be322011-07-01 22:53:31 -0700681 DELEGATE(Compiled);
Loganbe79ada2011-01-13 01:33:45 +0800682#undef DELEGATE
Logan89eb47f2011-01-07 10:45:16 +0800683
Shih-wei Liaod50be322011-07-01 22:53:31 -0700684 default: {
685 mErrorCode = BCC_INVALID_OPERATION;
686 }
Logan89eb47f2011-01-07 10:45:16 +0800687 }
Logancf3e5212010-12-29 01:44:55 +0800688}
689
Joseph Wenf36637f2011-07-06 18:27:12 -0700690void Script::getExportFuncNameList(std::vector<std::string> &funcList) {
691 switch (mStatus) {
692 case ScriptStatus::Compiled: {
693 return mCompiled->getExportFuncNameList(funcList);
694 }
695
696 default: {
697 mErrorCode = BCC_INVALID_OPERATION;
698 }
699 }
700}
701
Stephen Hinescc366e52012-02-21 17:22:04 -0800702void Script::getExportForEachList(size_t funcListSize, void **funcList) {
703 switch (mStatus) {
704#define DELEGATE(STATUS) \
705 case ScriptStatus::STATUS: \
706 m##STATUS->getExportForEachList(funcListSize, funcList); \
707 break;
708
709#if USE_CACHE
710 DELEGATE(Cached);
711#endif
712
713 DELEGATE(Compiled);
714#undef DELEGATE
715
716 default: {
717 mErrorCode = BCC_INVALID_OPERATION;
718 }
719 }
720}
721
722void Script::getExportForEachNameList(std::vector<std::string> &forEachList) {
723 switch (mStatus) {
724 case ScriptStatus::Compiled: {
725 return mCompiled->getExportForEachNameList(forEachList);
726 }
727
728 default: {
729 mErrorCode = BCC_INVALID_OPERATION;
730 }
731 }
732}
Logancf3e5212010-12-29 01:44:55 +0800733
Loganbe79ada2011-01-13 01:33:45 +0800734void Script::getPragmaList(size_t pragmaListSize,
735 char const **keyList,
736 char const **valueList) {
Logan89eb47f2011-01-07 10:45:16 +0800737 switch (mStatus) {
Loganbe79ada2011-01-13 01:33:45 +0800738#define DELEGATE(STATUS) \
Shih-wei Liaod50be322011-07-01 22:53:31 -0700739 case ScriptStatus::STATUS: \
740 m##STATUS->getPragmaList(pragmaListSize, keyList, valueList); \
741 break;
Logancf3e5212010-12-29 01:44:55 +0800742
Logan35849002011-01-15 07:30:43 +0800743#if USE_CACHE
Shih-wei Liaod50be322011-07-01 22:53:31 -0700744 DELEGATE(Cached);
Logan35849002011-01-15 07:30:43 +0800745#endif
746
Shih-wei Liaod50be322011-07-01 22:53:31 -0700747 DELEGATE(Compiled);
Loganbe79ada2011-01-13 01:33:45 +0800748#undef DELEGATE
Logan89eb47f2011-01-07 10:45:16 +0800749
Shih-wei Liaod50be322011-07-01 22:53:31 -0700750 default: {
751 mErrorCode = BCC_INVALID_OPERATION;
752 }
Logan89eb47f2011-01-07 10:45:16 +0800753 }
Logancf3e5212010-12-29 01:44:55 +0800754}
755
756
Loganf340bf72011-01-14 17:51:40 +0800757void Script::getFuncInfoList(size_t funcInfoListSize,
758 FuncInfo *funcInfoList) {
Logan89eb47f2011-01-07 10:45:16 +0800759 switch (mStatus) {
Loganbe79ada2011-01-13 01:33:45 +0800760#define DELEGATE(STATUS) \
Shih-wei Liaod50be322011-07-01 22:53:31 -0700761 case ScriptStatus::STATUS: \
762 m##STATUS->getFuncInfoList(funcInfoListSize, funcInfoList); \
763 break;
Logancf3e5212010-12-29 01:44:55 +0800764
Logan35849002011-01-15 07:30:43 +0800765#if USE_CACHE
Shih-wei Liaod50be322011-07-01 22:53:31 -0700766 DELEGATE(Cached);
Logan35849002011-01-15 07:30:43 +0800767#endif
768
Shih-wei Liaod50be322011-07-01 22:53:31 -0700769 DELEGATE(Compiled);
Loganbe79ada2011-01-13 01:33:45 +0800770#undef DELEGATE
Logan89eb47f2011-01-07 10:45:16 +0800771
Shih-wei Liaod50be322011-07-01 22:53:31 -0700772 default: {
773 mErrorCode = BCC_INVALID_OPERATION;
774 }
Logan89eb47f2011-01-07 10:45:16 +0800775 }
Logancf3e5212010-12-29 01:44:55 +0800776}
777
Stephen Hines071288a2011-01-27 14:38:26 -0800778
779void Script::getObjectSlotList(size_t objectSlotListSize,
780 uint32_t *objectSlotList) {
781 switch (mStatus) {
Shih-wei Liaod50be322011-07-01 22:53:31 -0700782#define DELEGATE(STATUS) \
783 case ScriptStatus::STATUS: \
784 m##STATUS->getObjectSlotList(objectSlotListSize, objectSlotList); \
785 break;
Stephen Hines071288a2011-01-27 14:38:26 -0800786
787#if USE_CACHE
Shih-wei Liaod50be322011-07-01 22:53:31 -0700788 DELEGATE(Cached);
Stephen Hines071288a2011-01-27 14:38:26 -0800789#endif
790
Shih-wei Liaod50be322011-07-01 22:53:31 -0700791 DELEGATE(Compiled);
Stephen Hines071288a2011-01-27 14:38:26 -0800792#undef DELEGATE
793
Shih-wei Liaod50be322011-07-01 22:53:31 -0700794 default: {
795 mErrorCode = BCC_INVALID_OPERATION;
796 }
Stephen Hines071288a2011-01-27 14:38:26 -0800797 }
798}
799
800
Logan Chiend2a5f302011-07-19 20:32:25 +0800801#if USE_OLD_JIT
Logana27a83f2011-01-07 10:25:48 +0800802char *Script::getContext() {
803 switch (mStatus) {
Shih-wei Liaob65410d2011-06-19 11:11:48 -0700804
Logan35849002011-01-15 07:30:43 +0800805#if USE_CACHE
Shih-wei Liaod50be322011-07-01 22:53:31 -0700806 case ScriptStatus::Cached: {
807 return mCached->getContext();
808 }
Logan35849002011-01-15 07:30:43 +0800809#endif
Shih-wei Liaob65410d2011-06-19 11:11:48 -0700810
Shih-wei Liaod50be322011-07-01 22:53:31 -0700811 case ScriptStatus::Compiled: {
812 return mCompiled->getContext();
813 }
Logana27a83f2011-01-07 10:25:48 +0800814
Shih-wei Liaod50be322011-07-01 22:53:31 -0700815 default: {
816 mErrorCode = BCC_INVALID_OPERATION;
817 return NULL;
818 }
Logan02286cb2011-01-07 00:30:47 +0800819 }
Logan02286cb2011-01-07 00:30:47 +0800820}
Logan Chiend2a5f302011-07-19 20:32:25 +0800821#endif
Logan02286cb2011-01-07 00:30:47 +0800822
Logancf3e5212010-12-29 01:44:55 +0800823
Shih-wei Liaoce82d492011-01-20 12:34:03 -0800824int Script::registerSymbolCallback(BCCSymbolLookupFn pFn, void *pContext) {
Logancf3e5212010-12-29 01:44:55 +0800825 mpExtSymbolLookupFn = pFn;
826 mpExtSymbolLookupFnContext = pContext;
827
Logan7d2219f2011-01-06 06:19:25 +0800828 if (mStatus != ScriptStatus::Unknown) {
Logancf3e5212010-12-29 01:44:55 +0800829 mErrorCode = BCC_INVALID_OPERATION;
Steve Block10c14122012-01-08 10:15:06 +0000830 ALOGE("Invalid operation: %s\n", __func__);
Shih-wei Liaoce82d492011-01-20 12:34:03 -0800831 return 1;
Logancf3e5212010-12-29 01:44:55 +0800832 }
Shih-wei Liaoce82d492011-01-20 12:34:03 -0800833 return 0;
Logancf3e5212010-12-29 01:44:55 +0800834}
Shih-wei Liaob65410d2011-06-19 11:11:48 -0700835
Shih-wei Liaoabc7f512012-01-18 00:34:07 -0800836bool Script::isCacheable() const {
837#if USE_CACHE
838 if (getBooleanProp("debug.bcc.nocache")) {
839 // Android system environment property: Disables the cache mechanism by
840 // setting "debug.bcc.nocache". So we will not load the cache file any
841 // way.
842 return false;
843 }
844
845 if (mCacheDir.empty() || mCacheName.empty()) {
846 // The application developer has not specified the cachePath, so
847 // we don't know where to open the cache file.
848 return false;
849 }
850
851 return true;
852#else
853 return false;
854#endif
855}
856
Shih-wei Liao5e3e0ce2011-06-17 13:59:46 -0700857#if USE_MCJIT
858size_t Script::getELFSize() const {
859 switch (mStatus) {
Shih-wei Liaod50be322011-07-01 22:53:31 -0700860 case ScriptStatus::Compiled: {
861 return mCompiled->getELFSize();
862 }
Daniel Malea094881f2011-12-14 17:39:16 -0500863#if USE_CACHE
864 case ScriptStatus::Cached: {
865 return mCached->getELFSize();
866 }
867#endif
Shih-wei Liaod50be322011-07-01 22:53:31 -0700868 default: {
869 return 0;
870 }
Shih-wei Liao5e3e0ce2011-06-17 13:59:46 -0700871 }
Shih-wei Liao5e3e0ce2011-06-17 13:59:46 -0700872}
873
874const char *Script::getELF() const {
875 switch (mStatus) {
Shih-wei Liaod50be322011-07-01 22:53:31 -0700876 case ScriptStatus::Compiled: {
877 return mCompiled->getELF();
878 }
Daniel Malea094881f2011-12-14 17:39:16 -0500879#if USE_CACHE
880 case ScriptStatus::Cached: {
881 return mCached->getELF();
882 }
883#endif
Shih-wei Liaod50be322011-07-01 22:53:31 -0700884 default: {
885 return NULL;
886 }
Shih-wei Liao5e3e0ce2011-06-17 13:59:46 -0700887 }
888}
889#endif
Logancf3e5212010-12-29 01:44:55 +0800890
891} // namespace bcc