blob: 45f4bb314a319bbe7929ebee139c16b92912008f [file] [log] [blame]
Logan1f028c02010-11-27 01:02:48 +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
Logan1f028c02010-11-27 01:02:48 +080020#if defined(__arm__)
21# define DEFAULT_ARM_CODEGEN
22# define PROVIDE_ARM_CODEGEN
23#elif defined(__i386__)
24# define DEFAULT_X86_CODEGEN
25# define PROVIDE_X86_CODEGEN
26#elif defined(__x86_64__)
27# define DEFAULT_X64_CODEGEN
28# define PROVIDE_X64_CODEGEN
29#endif
30
31#if defined(FORCE_ARM_CODEGEN)
32# define DEFAULT_ARM_CODEGEN
33# undef DEFAULT_X86_CODEGEN
34# undef DEFAULT_X64_CODEGEN
35# define PROVIDE_ARM_CODEGEN
36# undef PROVIDE_X86_CODEGEN
37# undef PROVIDE_X64_CODEGEN
38#elif defined(FORCE_X86_CODEGEN)
39# undef DEFAULT_ARM_CODEGEN
40# define DEFAULT_X86_CODEGEN
41# undef DEFAULT_X64_CODEGEN
42# undef PROVIDE_ARM_CODEGEN
43# define PROVIDE_X86_CODEGEN
44# undef PROVIDE_X64_CODEGEN
45#elif defined(FORCE_X64_CODEGEN)
46# undef DEFAULT_ARM_CODEGEN
47# undef DEFAULT_X86_CODEGEN
48# define DEFAULT_X64_CODEGEN
49# undef PROVIDE_ARM_CODEGEN
50# undef PROVIDE_X86_CODEGEN
51# define PROVIDE_X64_CODEGEN
52#endif
53
54#if defined(DEFAULT_ARM_CODEGEN)
Logandf23afa2010-11-27 11:04:54 +080055# define TARGET_TRIPLE_STRING "armv7-none-linux-gnueabi"
Logan1f028c02010-11-27 01:02:48 +080056#elif defined(DEFAULT_X86_CODEGEN)
Logandf23afa2010-11-27 11:04:54 +080057# define TARGET_TRIPLE_STRING "i686-unknown-linux"
Logan1f028c02010-11-27 01:02:48 +080058#elif defined(DEFAULT_X64_CODEGEN)
Logandf23afa2010-11-27 11:04:54 +080059# define TARGET_TRIPLE_STRING "x86_64-unknown-linux"
Logan1f028c02010-11-27 01:02:48 +080060#endif
61
62#if (defined(__VFP_FP__) && !defined(__SOFTFP__))
63# define ARM_USE_VFP
64#endif
65
Loganc4395232010-11-27 18:54:17 +080066#include "Compiler.h"
Logan1f028c02010-11-27 01:02:48 +080067
Loganeb3d12b2010-12-16 06:20:18 +080068#include "ContextManager.h"
69
Logandf23afa2010-11-27 11:04:54 +080070#include "llvm/ADT/StringRef.h"
Logan1f028c02010-11-27 01:02:48 +080071
Logandf23afa2010-11-27 11:04:54 +080072#include "llvm/Analysis/Passes.h"
Logan1f028c02010-11-27 01:02:48 +080073
Logan1f028c02010-11-27 01:02:48 +080074#include "llvm/Bitcode/ReaderWriter.h"
75
Logan1f028c02010-11-27 01:02:48 +080076#include "llvm/CodeGen/Passes.h"
Logan1f028c02010-11-27 01:02:48 +080077#include "llvm/CodeGen/RegAllocRegistry.h"
78#include "llvm/CodeGen/SchedulerRegistry.h"
Logan1f028c02010-11-27 01:02:48 +080079
Logandf23afa2010-11-27 11:04:54 +080080#include "llvm/Transforms/IPO.h"
81#include "llvm/Transforms/Scalar.h"
82
83#include "llvm/Target/SubtargetFeature.h"
84#include "llvm/Target/TargetData.h"
85#include "llvm/Target/TargetMachine.h"
86#include "llvm/Target/TargetOptions.h"
87#include "llvm/Target/TargetRegistry.h"
88#include "llvm/Target/TargetSelect.h"
89
90#include "llvm/Support/ErrorHandling.h"
91#include "llvm/Support/MemoryBuffer.h"
92
93#include "llvm/GlobalValue.h"
94#include "llvm/Linker.h"
95#include "llvm/LLVMContext.h"
96#include "llvm/Metadata.h"
97#include "llvm/Module.h"
98#include "llvm/PassManager.h"
99#include "llvm/Value.h"
100
101#include <errno.h>
102#include <sys/file.h>
Logandf23afa2010-11-27 11:04:54 +0800103#include <sys/stat.h>
104#include <sys/types.h>
105#include <unistd.h>
106
107#include <string>
108#include <vector>
Logan1f028c02010-11-27 01:02:48 +0800109
Logandf23afa2010-11-27 11:04:54 +0800110namespace {
Logan1f028c02010-11-27 01:02:48 +0800111
112#define TEMP_FAILURE_RETRY1(exp) ({ \
113 typeof (exp) _rc; \
114 do { \
115 _rc = (exp); \
116 } while (_rc == -1 && errno == EINTR); \
117 _rc; })
118
119
Logandf23afa2010-11-27 11:04:54 +0800120int sysWriteFully(int fd, const void* buf, size_t count, const char* logMsg) {
Logan1f028c02010-11-27 01:02:48 +0800121 while (count != 0) {
122 ssize_t actual = TEMP_FAILURE_RETRY1(write(fd, buf, count));
123 if (actual < 0) {
124 int err = errno;
125 LOGE("%s: write failed: %s\n", logMsg, strerror(err));
126 return err;
127 } else if (actual != (ssize_t) count) {
128 LOGD("%s: partial write (will retry): (%d of %zd)\n",
129 logMsg, (int) actual, count);
130 buf = (const void*) (((const uint8_t*) buf) + actual);
131 }
132 count -= actual;
133 }
134
135 return 0;
136}
137
Logan9d94f162010-12-07 12:39:25 +0800138inline uint32_t statModifyTime(char const *filepath) {
139 struct stat st;
140
141 if (stat(filepath, &st) < 0) {
142 LOGE("Unable to stat \'%s\', with reason: %s\n", filepath, strerror(errno));
143 return 0;
144 }
145
146 return static_cast<uint32_t>(st.st_mtime);
147}
148
149static char const libRSPath[] = "/system/lib/libRS.so";
150
151static char const libBccPath[] = "/system/lib/libbcc.so";
152
Logandf23afa2010-11-27 11:04:54 +0800153} // namespace anonymous
154
Logan1f028c02010-11-27 01:02:48 +0800155
156namespace bcc {
157
158//////////////////////////////////////////////////////////////////////////////
159// BCC Compiler Static Variables
160//////////////////////////////////////////////////////////////////////////////
161
162bool Compiler::GlobalInitialized = false;
163
Logan1f028c02010-11-27 01:02:48 +0800164// Code generation optimization level for the compiler
165llvm::CodeGenOpt::Level Compiler::CodeGenOptLevel;
166
167std::string Compiler::Triple;
168
169std::string Compiler::CPU;
170
171std::vector<std::string> Compiler::Features;
172
173// The named of metadata node that pragma resides (should be synced with
174// slang.cpp)
175const llvm::StringRef Compiler::PragmaMetadataName = "#pragma";
176
177// The named of metadata node that export variable name resides (should be
178// synced with slang_rs_metadata.h)
179const llvm::StringRef Compiler::ExportVarMetadataName = "#rs_export_var";
180
181// The named of metadata node that export function name resides (should be
182// synced with slang_rs_metadata.h)
183const llvm::StringRef Compiler::ExportFuncMetadataName = "#rs_export_func";
184
185
186//////////////////////////////////////////////////////////////////////////////
187// Compiler
188//////////////////////////////////////////////////////////////////////////////
189
190void Compiler::GlobalInitialization() {
191 if (GlobalInitialized)
192 return;
193
194 // if (!llvm::llvm_is_multithreaded())
195 // llvm::llvm_start_multithreaded();
196
197 // Set Triple, CPU and Features here
198 Triple = TARGET_TRIPLE_STRING;
199
200 // TODO(sliao): NEON for JIT
201 // Features.push_back("+neon");
202 // Features.push_back("+vmlx");
203 // Features.push_back("+neonfp");
204 Features.push_back("+vfp3");
205 Features.push_back("+d16");
206
207#if defined(DEFAULT_ARM_CODEGEN) || defined(PROVIDE_ARM_CODEGEN)
208 LLVMInitializeARMTargetInfo();
209 LLVMInitializeARMTarget();
210#if defined(USE_DISASSEMBLER)
211 LLVMInitializeARMDisassembler();
212 LLVMInitializeARMAsmPrinter();
213#endif
214#endif
215
216#if defined(DEFAULT_X86_CODEGEN) || defined(PROVIDE_X86_CODEGEN)
217 LLVMInitializeX86TargetInfo();
218 LLVMInitializeX86Target();
219#if defined(USE_DISASSEMBLER)
220 LLVMInitializeX86Disassembler();
221 LLVMInitializeX86AsmPrinter();
222#endif
223#endif
224
225#if defined(DEFAULT_X64_CODEGEN) || defined(PROVIDE_X64_CODEGEN)
226 LLVMInitializeX86TargetInfo();
227 LLVMInitializeX86Target();
228#if defined(USE_DISASSEMBLER)
229 LLVMInitializeX86Disassembler();
230 LLVMInitializeX86AsmPrinter();
231#endif
232#endif
233
234 // -O0: llvm::CodeGenOpt::None
235 // -O1: llvm::CodeGenOpt::Less
236 // -O2: llvm::CodeGenOpt::Default
237 // -O3: llvm::CodeGenOpt::Aggressive
Shih-wei Liao72f67a62010-12-14 13:36:15 -0800238 CodeGenOptLevel = llvm::CodeGenOpt::Aggressive;
Logan1f028c02010-11-27 01:02:48 +0800239
240 // Below are the global settings to LLVM
241
242 // Disable frame pointer elimination optimization
243 llvm::NoFramePointerElim = false;
244
245 // Use hardfloat ABI
246 //
247 // TODO(all): Need to detect the CPU capability and decide whether to use
248 // softfp. To use softfp, change following 2 lines to
249 //
250 // llvm::FloatABIType = llvm::FloatABI::Soft;
251 // llvm::UseSoftFloat = true;
252 //
Shih-wei Liaoe728cb82010-12-15 15:20:47 -0800253 llvm::FloatABIType = llvm::FloatABI::Soft;
Logan1f028c02010-11-27 01:02:48 +0800254 llvm::UseSoftFloat = false;
255
256 // BCC needs all unknown symbols resolved at JIT/compilation time.
257 // So we don't need any dynamic relocation model.
258 llvm::TargetMachine::setRelocationModel(llvm::Reloc::Static);
259
260#if defined(DEFAULT_X64_CODEGEN)
261 // Data address in X86_64 architecture may reside in a far-away place
262 llvm::TargetMachine::setCodeModel(llvm::CodeModel::Medium);
263#else
264 // This is set for the linker (specify how large of the virtual addresses
265 // we can access for all unknown symbols.)
266 llvm::TargetMachine::setCodeModel(llvm::CodeModel::Small);
267#endif
268
269 // Register the scheduler
270 llvm::RegisterScheduler::setDefault(llvm::createDefaultScheduler);
271
272 // Register allocation policy:
273 // createFastRegisterAllocator: fast but bad quality
274 // createLinearScanRegisterAllocator: not so fast but good quality
275 llvm::RegisterRegAlloc::setDefault
276 ((CodeGenOptLevel == llvm::CodeGenOpt::None) ?
277 llvm::createFastRegisterAllocator :
278 llvm::createLinearScanRegisterAllocator);
279
280 GlobalInitialized = true;
281}
282
283
284void Compiler::LLVMErrorHandler(void *UserData, const std::string &Message) {
285 std::string *Error = static_cast<std::string*>(UserData);
286 Error->assign(Message);
287 LOGE("%s", Message.c_str());
288 exit(1);
289}
290
291
292CodeMemoryManager *Compiler::createCodeMemoryManager() {
293 mCodeMemMgr.reset(new CodeMemoryManager());
294 return mCodeMemMgr.get();
295}
296
297
298CodeEmitter *Compiler::createCodeEmitter() {
299 mCodeEmitter.reset(new CodeEmitter(mCodeMemMgr.take()));
300 return mCodeEmitter.get();
301}
302
303
304Compiler::Compiler()
305 : mUseCache(false),
306 mCacheNew(false),
307 mCacheFd(-1),
308 mCacheMapAddr(NULL),
309 mCacheHdr(NULL),
310 mCacheSize(0),
311 mCacheDiff(0),
312 mCodeDataAddr(NULL),
313 mpSymbolLookupFn(NULL),
314 mpSymbolLookupContext(NULL),
315 mContext(NULL),
316 mModule(NULL),
317 mHasLinked(false) /* Turn off linker */ {
318 llvm::remove_fatal_error_handler();
319 llvm::install_fatal_error_handler(LLVMErrorHandler, &mError);
320 mContext = new llvm::LLVMContext();
321 return;
322}
323
324
325int Compiler::readBC(const char *bitcode,
326 size_t bitcodeSize,
Shih-wei Liaoe6a18512010-12-09 12:38:10 -0800327 const BCCchar *resName,
328 const BCCchar *cacheDir) {
Logan1f028c02010-11-27 01:02:48 +0800329 GlobalInitialization();
330
331 if (resName) {
332 // Turn on mUseCache mode iff
333 // 1. Has resName
334 // and, assuming USE_RELOCATE is false:
335 // 2. Later running code doesn't violate the following condition:
336 // mCodeDataAddr (set in loadCacheFile()) ==
337 // mCacheHdr->cachedCodeDataAddr
338 //
339 // BTW, this condition is achievable only when in the earlier
340 // cache-generating run,
341 // mpCodeMem == BccCodeAddr - MaxCodeSize - MaxGlobalVarSize,
342 // which means the mmap'ed is in the reserved area,
343 //
344 // Note: Upon violation, mUseCache will be set back to false.
345 mUseCache = true;
346
Shih-wei Liaoe6a18512010-12-09 12:38:10 -0800347 mCacheFd = openCacheFile(resName, cacheDir, true /* createIfMissing */);
Logan1f028c02010-11-27 01:02:48 +0800348 if (mCacheFd >= 0 && !mCacheNew) { // Just use cache file
Logan139dc3c2010-12-03 01:32:05 +0800349 return -mCacheFd - 1;
Logan1f028c02010-11-27 01:02:48 +0800350 }
351 }
352
353 llvm::OwningPtr<llvm::MemoryBuffer> MEM;
354
355 if (bitcode == NULL || bitcodeSize <= 0)
356 return 0;
357
358 // Package input to object MemoryBuffer
359 MEM.reset(llvm::MemoryBuffer::getMemBuffer(
360 llvm::StringRef(bitcode, bitcodeSize)));
361
362 if (MEM.get() == NULL) {
363 setError("Error reading input program bitcode into memory");
364 return hasError();
365 }
366
367 // Read the input Bitcode as a Module
368 mModule = llvm::ParseBitcodeFile(MEM.get(), *mContext, &mError);
369 MEM.reset();
370 return hasError();
371}
372
373
374int Compiler::linkBC(const char *bitcode, size_t bitcodeSize) {
375 llvm::OwningPtr<llvm::MemoryBuffer> MEM;
376
377 if (bitcode == NULL || bitcodeSize <= 0)
378 return 0;
379
380 if (mModule == NULL) {
381 setError("No module presents for linking");
382 return hasError();
383 }
384
385 MEM.reset(llvm::MemoryBuffer::getMemBuffer(
386 llvm::StringRef(bitcode, bitcodeSize)));
387
388 if (MEM.get() == NULL) {
389 setError("Error reading input library bitcode into memory");
390 return hasError();
391 }
392
393 llvm::OwningPtr<llvm::Module> Lib(llvm::ParseBitcodeFile(MEM.get(),
394 *mContext,
395 &mError));
396 if (Lib.get() == NULL)
397 return hasError();
398
399 if (llvm::Linker::LinkModules(mModule, Lib.take(), &mError))
400 return hasError();
401
402 // Everything for linking should be settled down here with no error occurs
403 mHasLinked = true;
404 return hasError();
405}
406
407
408// interface for bccLoadBinary()
409int Compiler::loadCacheFile() {
410 // Check File Descriptor
411 if (mCacheFd < 0) {
412 LOGE("loading cache from invalid mCacheFd = %d\n", (int)mCacheFd);
413 goto giveup;
414 }
415
416 // Check File Size
417 struct stat statCacheFd;
418 if (fstat(mCacheFd, &statCacheFd) < 0) {
419 LOGE("unable to stat mCacheFd = %d\n", (int)mCacheFd);
420 goto giveup;
421 }
422
423 mCacheSize = statCacheFd.st_size;
424
425 if (mCacheSize < sizeof(oBCCHeader) ||
426 mCacheSize <= MaxCodeSize + MaxGlobalVarSize) {
427 LOGE("mCacheFd %d is too small to be correct\n", (int)mCacheFd);
428 goto giveup;
429 }
430
431 if (lseek(mCacheFd, 0, SEEK_SET) != 0) {
432 LOGE("Unable to seek to 0: %s\n", strerror(errno));
433 goto giveup;
434 }
435
436 // Part 1. Deal with the non-codedata section first
437 {
438 // Read cached file and perform quick integrity check
439
440 off_t heuristicCodeOffset = mCacheSize - MaxCodeSize - MaxGlobalVarSize;
441 LOGW("TODO(sliao)@loadCacheFile: mCacheSize=%x, heuristicCodeOffset=%llx",
442 (unsigned int)mCacheSize,
443 (unsigned long long int)heuristicCodeOffset);
444
445 mCacheMapAddr = (char *)malloc(heuristicCodeOffset);
446 if (!mCacheMapAddr) {
447 flock(mCacheFd, LOCK_UN);
448 LOGE("allocation failed.\n");
449 goto bail;
450 }
451
452 size_t nread = TEMP_FAILURE_RETRY1(read(mCacheFd, mCacheMapAddr,
453 heuristicCodeOffset));
454 if (nread != (size_t)heuristicCodeOffset) {
455 LOGE("read(mCacheFd) failed\n");
456 goto bail;
457 }
458
459 mCacheHdr = reinterpret_cast<oBCCHeader *>(mCacheMapAddr);
460 // Sanity check
461 if (mCacheHdr->codeOffset != (uint32_t)heuristicCodeOffset) {
462 LOGE("assertion failed: heuristic code offset is not correct.\n");
463 goto bail;
464 }
465 LOGW("TODO(sliao): mCacheHdr->cachedCodeDataAddr=%x", mCacheHdr->cachedCodeDataAddr);
466 LOGW("mCacheHdr->rootAddr=%x", mCacheHdr->rootAddr);
467 LOGW("mCacheHdr->initAddr=%x", mCacheHdr->initAddr);
468 LOGW("mCacheHdr->codeOffset=%x", mCacheHdr->codeOffset);
469 LOGW("mCacheHdr->codeSize=%x", mCacheHdr->codeSize);
470
471 // Verify the Cache File
472 if (memcmp(mCacheHdr->magic, OBCC_MAGIC, 4) != 0) {
473 LOGE("bad magic word\n");
474 goto bail;
475 }
476
477 if (memcmp(mCacheHdr->magicVersion, OBCC_MAGIC_VERS, 4) != 0) {
478 LOGE("bad oBCC version 0x%08x\n",
479 *reinterpret_cast<uint32_t *>(mCacheHdr->magicVersion));
480 goto bail;
481 }
482
483 if (mCacheSize < mCacheHdr->relocOffset +
Logan7cc1baf2010-11-28 23:46:11 +0800484 mCacheHdr->relocCount * sizeof(oBCCRelocEntry)) {
Logan1f028c02010-11-27 01:02:48 +0800485 LOGE("relocate table overflow\n");
486 goto bail;
487 }
488
489 if (mCacheSize < mCacheHdr->exportVarsOffset +
Logan7cc1baf2010-11-28 23:46:11 +0800490 mCacheHdr->exportVarsCount * sizeof(uint32_t)) {
Logan1f028c02010-11-27 01:02:48 +0800491 LOGE("export variables table overflow\n");
492 goto bail;
493 }
494
495 if (mCacheSize < mCacheHdr->exportFuncsOffset +
Logan7cc1baf2010-11-28 23:46:11 +0800496 mCacheHdr->exportFuncsCount * sizeof(uint32_t)) {
Logan1f028c02010-11-27 01:02:48 +0800497 LOGE("export functions table overflow\n");
498 goto bail;
499 }
500
501 if (mCacheSize < mCacheHdr->exportPragmasOffset +
Logan7cc1baf2010-11-28 23:46:11 +0800502 mCacheHdr->exportPragmasSize) {
Logan1f028c02010-11-27 01:02:48 +0800503 LOGE("export pragmas table overflow\n");
504 goto bail;
505 }
506
507 if (mCacheSize < mCacheHdr->codeOffset + mCacheHdr->codeSize) {
508 LOGE("code cache overflow\n");
509 goto bail;
510 }
511
512 if (mCacheSize < mCacheHdr->dataOffset + mCacheHdr->dataSize) {
513 LOGE("data (global variable) cache overflow\n");
514 goto bail;
515 }
516
517 long pagesize = sysconf(_SC_PAGESIZE);
518 if (mCacheHdr->codeOffset % pagesize != 0) {
519 LOGE("code offset must aligned to pagesize\n");
520 goto bail;
521 }
522 }
523
524 // Part 2. Deal with the codedata section
525 {
526 long pagesize = sysconf(_SC_PAGESIZE);
527
528 if (mCacheHdr->cachedCodeDataAddr % pagesize == 0) {
Loganeb3d12b2010-12-16 06:20:18 +0800529 char *addr = reinterpret_cast<char *>(mCacheHdr->cachedCodeDataAddr);
Logan1f028c02010-11-27 01:02:48 +0800530
Loganeb3d12b2010-12-16 06:20:18 +0800531 // Try to allocate context at cached address directly.
532 mCodeDataAddr = allocateContext(addr, mCacheFd, mCacheHdr->codeOffset);
Logan1f028c02010-11-27 01:02:48 +0800533
Loganeb3d12b2010-12-16 06:20:18 +0800534 if (!mCodeDataAddr) {
535 // Unable to allocate at cached address. Give up.
536 flock(mCacheFd, LOCK_UN);
537 goto bail;
538 }
Logan1f028c02010-11-27 01:02:48 +0800539
540#if 1
Loganeb3d12b2010-12-16 06:20:18 +0800541 // Check the checksum of code and data
542 {
543 uint32_t sum = mCacheHdr->checksum;
544 uint32_t *ptr = (uint32_t *)mCodeDataAddr;
Logan1f028c02010-11-27 01:02:48 +0800545
Loganeb3d12b2010-12-16 06:20:18 +0800546 for (size_t i = 0; i < BCC_CONTEXT_SIZE / sizeof(uint32_t); ++i) {
547 sum ^= *ptr++;
Logan1f028c02010-11-27 01:02:48 +0800548 }
Loganeb3d12b2010-12-16 06:20:18 +0800549
550 if (sum != 0) {
551 LOGE("Checksum check failed\n");
552 goto bail;
553 }
554
555 LOGI("Passed checksum even parity verification.\n");
556 }
Logan1f028c02010-11-27 01:02:48 +0800557#endif
558
Loganeb3d12b2010-12-16 06:20:18 +0800559 flock(mCacheFd, LOCK_UN);
560 return 0; // loadCacheFile succeed!
Logan1f028c02010-11-27 01:02:48 +0800561 }
562 }
563
564#if !USE_RELOCATE
565 // Note: Since this build does not support relocation, we have no
566 // choose but give up to load the cached file, and recompile the
567 // code.
568
569 flock(mCacheFd, LOCK_UN);
570 goto bail;
571#else
572
573 // Note: Currently, relocation code is not working. Give up now.
574 flock(mCacheFd, LOCK_UN);
575 goto bail;
576
577 // TODO(logan): Following code is not working. Don't use them.
578 // And rewrite them asap.
579#if 0
580 {
581 // Try to allocate at arbitary address. And perform relocation.
582 mCacheMapAddr = (char *) mmap(0,
583 mCacheSize,
584 PROT_READ | PROT_EXEC | PROT_WRITE,
585 MAP_PRIVATE,
586 mCacheFd,
587 0);
588
589 if (mCacheMapAddr == MAP_FAILED) {
590 LOGE("unable to mmap .oBBC cache: %s\n", strerror(errno));
591 flock(mCacheFd, LOCK_UN);
592 goto giveup;
593 }
594
595 flock(mCacheFd, LOCK_UN);
596 mCodeDataAddr = mCacheMapAddr + mCacheHdr->codeOffset;
597
598 // Relocate
599 mCacheDiff = mCodeDataAddr -
600 reinterpret_cast<char *>(mCacheHdr->cachedCodeDataAddr);
601
602 if (mCacheDiff) { // To relocate
603 if (mCacheHdr->rootAddr) {
604 mCacheHdr->rootAddr += mCacheDiff;
605 }
606
607 if (mCacheHdr->initAddr) {
608 mCacheHdr->initAddr += mCacheDiff;
609 }
610
611 oBCCRelocEntry *cachedRelocTable =
612 reinterpret_cast<oBCCRelocEntry *>(mCacheMapAddr +
613 mCacheHdr->relocOffset);
614
615 std::vector<llvm::MachineRelocation> relocations;
616
617 // Read in the relocs
618 for (size_t i = 0; i < mCacheHdr->relocCount; i++) {
619 oBCCRelocEntry *entry = &cachedRelocTable[i];
620
621 llvm::MachineRelocation reloc =
622 llvm::MachineRelocation::getGV((uintptr_t)entry->relocOffset,
623 (unsigned)entry->relocType, 0, 0);
624
625 reloc.setResultPointer(
626 reinterpret_cast<char *>(entry->cachedResultAddr) + mCacheDiff);
627
628 relocations.push_back(reloc);
629 }
630
631 // Rewrite machine code using llvm::TargetJITInfo relocate
632 {
633 llvm::TargetMachine *TM = NULL;
634 const llvm::Target *Target;
635 std::string FeaturesStr;
636
637 // Create TargetMachine
638 Target = llvm::TargetRegistry::lookupTarget(Triple, mError);
639 if (hasError())
640 goto bail;
641
642 if (!CPU.empty() || !Features.empty()) {
643 llvm::SubtargetFeatures F;
644 F.setCPU(CPU);
645 for (std::vector<std::string>::const_iterator I = Features.begin(),
646 E = Features.end(); I != E; I++)
647 F.AddFeature(*I);
648 FeaturesStr = F.getString();
649 }
650
651 TM = Target->createTargetMachine(Triple, FeaturesStr);
652 if (TM == NULL) {
653 setError("Failed to create target machine implementation for the"
654 " specified triple '" + Triple + "'");
655 goto bail;
656 }
657
658 TM->getJITInfo()->relocate(mCodeDataAddr,
659 &relocations[0], relocations.size(),
660 (unsigned char *)mCodeDataAddr+MaxCodeSize);
661
662 if (mCodeEmitter.get()) {
663 mCodeEmitter->Disassemble(llvm::StringRef("cache"),
664 reinterpret_cast<uint8_t*>(mCodeDataAddr),
665 2 * 1024 /*MaxCodeSize*/,
666 false);
667 }
668
669 delete TM;
670 }
671 } // End of if (mCacheDiff)
672
673 return 0; // Success!
674 }
675#endif
676#endif
677
678bail:
679 if (mCacheMapAddr) {
680 free(mCacheMapAddr);
681 }
682
Loganeb3d12b2010-12-16 06:20:18 +0800683 if (mCodeDataAddr) {
684 deallocateContext(mCodeDataAddr);
Logan1f028c02010-11-27 01:02:48 +0800685 }
686
687 mCacheMapAddr = NULL;
688 mCacheHdr = NULL;
689 mCodeDataAddr = NULL;
690
691giveup:
692 return 1;
693}
694
695// interace for bccCompileBC()
696int Compiler::compile() {
697 llvm::TargetData *TD = NULL;
698
699 llvm::TargetMachine *TM = NULL;
700 const llvm::Target *Target;
701 std::string FeaturesStr;
702
703 llvm::FunctionPassManager *CodeGenPasses = NULL;
704
705 const llvm::NamedMDNode *PragmaMetadata;
706 const llvm::NamedMDNode *ExportVarMetadata;
707 const llvm::NamedMDNode *ExportFuncMetadata;
708
709 if (mModule == NULL) // No module was loaded
710 return 0;
711
712 // Create TargetMachine
713 Target = llvm::TargetRegistry::lookupTarget(Triple, mError);
714 if (hasError())
715 goto on_bcc_compile_error;
716
717 if (!CPU.empty() || !Features.empty()) {
718 llvm::SubtargetFeatures F;
719 F.setCPU(CPU);
Logana4994f52010-11-27 14:06:02 +0800720
721 for (std::vector<std::string>::const_iterator
722 I = Features.begin(), E = Features.end(); I != E; I++) {
Logan1f028c02010-11-27 01:02:48 +0800723 F.AddFeature(*I);
Logana4994f52010-11-27 14:06:02 +0800724 }
725
Logan1f028c02010-11-27 01:02:48 +0800726 FeaturesStr = F.getString();
727 }
728
729 TM = Target->createTargetMachine(Triple, FeaturesStr);
730 if (TM == NULL) {
731 setError("Failed to create target machine implementation for the"
732 " specified triple '" + Triple + "'");
733 goto on_bcc_compile_error;
734 }
735
736 // Create memory manager for creation of code emitter later.
737 if (!mCodeMemMgr.get() && !createCodeMemoryManager()) {
738 setError("Failed to startup memory management for further compilation");
739 goto on_bcc_compile_error;
740 }
741 mCodeDataAddr = (char *) (mCodeMemMgr.get()->getCodeMemBase());
742
743 // Create code emitter
744 if (!mCodeEmitter.get()) {
745 if (!createCodeEmitter()) {
746 setError("Failed to create machine code emitter to complete"
747 " the compilation");
748 goto on_bcc_compile_error;
749 }
750 } else {
751 // Reuse the code emitter
752 mCodeEmitter->reset();
753 }
754
755 mCodeEmitter->setTargetMachine(*TM);
756 mCodeEmitter->registerSymbolCallback(mpSymbolLookupFn,
757 mpSymbolLookupContext);
758
759 // Get target data from Module
760 TD = new llvm::TargetData(mModule);
761
762 // Load named metadata
763 ExportVarMetadata = mModule->getNamedMetadata(ExportVarMetadataName);
764 ExportFuncMetadata = mModule->getNamedMetadata(ExportFuncMetadataName);
765 PragmaMetadata = mModule->getNamedMetadata(PragmaMetadataName);
766
767 // Create LTO passes and run them on the mModule
768 if (mHasLinked) {
769 llvm::TimePassesIsEnabled = true; // TODO(all)
770 llvm::PassManager LTOPasses;
771 LTOPasses.add(new llvm::TargetData(*TD));
772
773 std::vector<const char*> ExportSymbols;
774
775 // A workaround for getting export variable and function name. Will refine
776 // it soon.
777 if (ExportVarMetadata) {
778 for (int i = 0, e = ExportVarMetadata->getNumOperands(); i != e; i++) {
779 llvm::MDNode *ExportVar = ExportVarMetadata->getOperand(i);
780 if (ExportVar != NULL && ExportVar->getNumOperands() > 1) {
781 llvm::Value *ExportVarNameMDS = ExportVar->getOperand(0);
782 if (ExportVarNameMDS->getValueID() == llvm::Value::MDStringVal) {
783 llvm::StringRef ExportVarName =
784 static_cast<llvm::MDString*>(ExportVarNameMDS)->getString();
785 ExportSymbols.push_back(ExportVarName.data());
786 }
787 }
788 }
789 }
790
791 if (ExportFuncMetadata) {
792 for (int i = 0, e = ExportFuncMetadata->getNumOperands(); i != e; i++) {
793 llvm::MDNode *ExportFunc = ExportFuncMetadata->getOperand(i);
794 if (ExportFunc != NULL && ExportFunc->getNumOperands() > 0) {
795 llvm::Value *ExportFuncNameMDS = ExportFunc->getOperand(0);
796 if (ExportFuncNameMDS->getValueID() == llvm::Value::MDStringVal) {
797 llvm::StringRef ExportFuncName =
798 static_cast<llvm::MDString*>(ExportFuncNameMDS)->getString();
799 ExportSymbols.push_back(ExportFuncName.data());
800 }
801 }
802 }
803 }
804 // root() and init() are born to be exported
805 ExportSymbols.push_back("root");
806 ExportSymbols.push_back("init");
807
808 // We now create passes list performing LTO. These are copied from
809 // (including comments) llvm::createStandardLTOPasses().
810
811 // Internalize all other symbols not listed in ExportSymbols
812 LTOPasses.add(llvm::createInternalizePass(ExportSymbols));
813
814 // Propagate constants at call sites into the functions they call. This
815 // opens opportunities for globalopt (and inlining) by substituting
816 // function pointers passed as arguments to direct uses of functions.
817 LTOPasses.add(llvm::createIPSCCPPass());
818
819 // Now that we internalized some globals, see if we can hack on them!
820 LTOPasses.add(llvm::createGlobalOptimizerPass());
821
822 // Linking modules together can lead to duplicated global constants, only
823 // keep one copy of each constant...
824 LTOPasses.add(llvm::createConstantMergePass());
825
826 // Remove unused arguments from functions...
827 LTOPasses.add(llvm::createDeadArgEliminationPass());
828
829 // Reduce the code after globalopt and ipsccp. Both can open up
830 // significant simplification opportunities, and both can propagate
831 // functions through function pointers. When this happens, we often have
832 // to resolve varargs calls, etc, so let instcombine do this.
833 LTOPasses.add(llvm::createInstructionCombiningPass());
834
835 // Inline small functions
836 LTOPasses.add(llvm::createFunctionInliningPass());
837
838 // Remove dead EH info.
839 LTOPasses.add(llvm::createPruneEHPass());
840
841 // Internalize the globals again after inlining
842 LTOPasses.add(llvm::createGlobalOptimizerPass());
843
844 // Remove dead functions.
845 LTOPasses.add(llvm::createGlobalDCEPass());
846
847 // If we didn't decide to inline a function, check to see if we can
848 // transform it to pass arguments by value instead of by reference.
849 LTOPasses.add(llvm::createArgumentPromotionPass());
850
851 // The IPO passes may leave cruft around. Clean up after them.
852 LTOPasses.add(llvm::createInstructionCombiningPass());
853 LTOPasses.add(llvm::createJumpThreadingPass());
854
855 // Break up allocas
856 LTOPasses.add(llvm::createScalarReplAggregatesPass());
857
858 // Run a few AA driven optimizations here and now, to cleanup the code.
859 LTOPasses.add(llvm::createFunctionAttrsPass()); // Add nocapture.
860 LTOPasses.add(llvm::createGlobalsModRefPass()); // IP alias analysis.
861
862 // Hoist loop invariants.
863 LTOPasses.add(llvm::createLICMPass());
864
865 // Remove redundancies.
866 LTOPasses.add(llvm::createGVNPass());
867
868 // Remove dead memcpys.
869 LTOPasses.add(llvm::createMemCpyOptPass());
870
871 // Nuke dead stores.
872 LTOPasses.add(llvm::createDeadStoreEliminationPass());
873
874 // Cleanup and simplify the code after the scalar optimizations.
875 LTOPasses.add(llvm::createInstructionCombiningPass());
876
877 LTOPasses.add(llvm::createJumpThreadingPass());
878
879 // Delete basic blocks, which optimization passes may have killed.
880 LTOPasses.add(llvm::createCFGSimplificationPass());
881
882 // Now that we have optimized the program, discard unreachable functions.
883 LTOPasses.add(llvm::createGlobalDCEPass());
884
885 LTOPasses.run(*mModule);
886 }
887
888 // Create code-gen pass to run the code emitter
889 CodeGenPasses = new llvm::FunctionPassManager(mModule);
890 CodeGenPasses->add(TD); // Will take the ownership of TD
891
892 if (TM->addPassesToEmitMachineCode(*CodeGenPasses,
893 *mCodeEmitter,
894 CodeGenOptLevel)) {
895 setError("The machine code emission is not supported by BCC on target '"
896 + Triple + "'");
897 goto on_bcc_compile_error;
898 }
899
900 // Run the pass (the code emitter) on every non-declaration function in the
901 // module
902 CodeGenPasses->doInitialization();
903 for (llvm::Module::iterator I = mModule->begin(), E = mModule->end();
904 I != E; I++) {
905 if (!I->isDeclaration()) {
906 CodeGenPasses->run(*I);
907 }
908 }
909
910 CodeGenPasses->doFinalization();
911
912 // Copy the global address mapping from code emitter and remapping
913 if (ExportVarMetadata) {
914 for (int i = 0, e = ExportVarMetadata->getNumOperands(); i != e; i++) {
915 llvm::MDNode *ExportVar = ExportVarMetadata->getOperand(i);
916 if (ExportVar != NULL && ExportVar->getNumOperands() > 1) {
917 llvm::Value *ExportVarNameMDS = ExportVar->getOperand(0);
918 if (ExportVarNameMDS->getValueID() == llvm::Value::MDStringVal) {
919 llvm::StringRef ExportVarName =
920 static_cast<llvm::MDString*>(ExportVarNameMDS)->getString();
921
922 CodeEmitter::global_addresses_const_iterator I, E;
923 for (I = mCodeEmitter->global_address_begin(),
924 E = mCodeEmitter->global_address_end();
925 I != E; I++) {
926 if (I->first->getValueID() != llvm::Value::GlobalVariableVal)
927 continue;
928 if (ExportVarName == I->first->getName()) {
929 mExportVars.push_back(I->second);
930 break;
931 }
932 }
933 if (I != mCodeEmitter->global_address_end())
934 continue; // found
935 }
936 }
937 // if reaching here, we know the global variable record in metadata is
938 // not found. So we make an empty slot
939 mExportVars.push_back(NULL);
940 }
941 assert((mExportVars.size() == ExportVarMetadata->getNumOperands()) &&
942 "Number of slots doesn't match the number of export variables!");
943 }
944
945 if (ExportFuncMetadata) {
946 for (int i = 0, e = ExportFuncMetadata->getNumOperands(); i != e; i++) {
947 llvm::MDNode *ExportFunc = ExportFuncMetadata->getOperand(i);
948 if (ExportFunc != NULL && ExportFunc->getNumOperands() > 0) {
949 llvm::Value *ExportFuncNameMDS = ExportFunc->getOperand(0);
950 if (ExportFuncNameMDS->getValueID() == llvm::Value::MDStringVal) {
951 llvm::StringRef ExportFuncName =
952 static_cast<llvm::MDString*>(ExportFuncNameMDS)->getString();
953 mExportFuncs.push_back(mCodeEmitter->lookup(ExportFuncName));
954 }
955 }
956 }
957 }
958
959 // Tell code emitter now can release the memory using during the JIT since
960 // we have done the code emission
961 mCodeEmitter->releaseUnnecessary();
962
963 // Finally, read pragma information from the metadata node of the @Module if
964 // any.
965 if (PragmaMetadata)
966 for (int i = 0, e = PragmaMetadata->getNumOperands(); i != e; i++) {
967 llvm::MDNode *Pragma = PragmaMetadata->getOperand(i);
968 if (Pragma != NULL &&
969 Pragma->getNumOperands() == 2 /* should have exactly 2 operands */) {
970 llvm::Value *PragmaNameMDS = Pragma->getOperand(0);
971 llvm::Value *PragmaValueMDS = Pragma->getOperand(1);
972
973 if ((PragmaNameMDS->getValueID() == llvm::Value::MDStringVal) &&
974 (PragmaValueMDS->getValueID() == llvm::Value::MDStringVal)) {
975 llvm::StringRef PragmaName =
976 static_cast<llvm::MDString*>(PragmaNameMDS)->getString();
977 llvm::StringRef PragmaValue =
978 static_cast<llvm::MDString*>(PragmaValueMDS)->getString();
979
980 mPragmas.push_back(
981 std::make_pair(std::string(PragmaName.data(),
982 PragmaName.size()),
983 std::string(PragmaValue.data(),
984 PragmaValue.size())));
985 }
986 }
987 }
988
989on_bcc_compile_error:
990 // LOGE("on_bcc_compiler_error");
991 if (CodeGenPasses) {
992 delete CodeGenPasses;
993 } else if (TD) {
994 delete TD;
995 }
996 if (TM)
997 delete TM;
998
999 if (mError.empty()) {
1000 if (mUseCache && mCacheFd >= 0 && mCacheNew) {
1001 genCacheFile();
1002 flock(mCacheFd, LOCK_UN);
1003 }
1004
1005 return false;
1006 }
1007
1008 // LOGE(getErrorMessage());
1009 return true;
1010}
1011
1012
1013// interface for bccGetScriptLabel()
1014void *Compiler::lookup(const char *name) {
1015 void *addr = NULL;
1016 if (mUseCache && mCacheFd >= 0 && !mCacheNew) {
1017 if (!strcmp(name, "root")) {
1018 addr = reinterpret_cast<void *>(mCacheHdr->rootAddr);
1019 } else if (!strcmp(name, "init")) {
1020 addr = reinterpret_cast<void *>(mCacheHdr->initAddr);
1021 }
1022 return addr;
1023 }
1024
1025 if (mCodeEmitter.get())
1026 // Find function pointer
1027 addr = mCodeEmitter->lookup(name);
1028 return addr;
1029}
1030
1031
1032// Interface for bccGetExportVars()
1033void Compiler::getExportVars(BCCsizei *actualVarCount,
1034 BCCsizei maxVarCount,
1035 BCCvoid **vars) {
1036 int varCount;
1037
1038 if (mUseCache && mCacheFd >= 0 && !mCacheNew) {
1039 varCount = static_cast<int>(mCacheHdr->exportVarsCount);
1040 if (actualVarCount)
1041 *actualVarCount = varCount;
1042 if (varCount > maxVarCount)
1043 varCount = maxVarCount;
1044 if (vars) {
1045 uint32_t *cachedVars = (uint32_t *)(mCacheMapAddr +
1046 mCacheHdr->exportVarsOffset);
1047
1048 for (int i = 0; i < varCount; i++) {
Logan7cc1baf2010-11-28 23:46:11 +08001049 *vars = (BCCvoid *)((char *)(*cachedVars) + mCacheDiff);
1050 vars++;
Logan1f028c02010-11-27 01:02:48 +08001051 cachedVars++;
1052 }
1053 }
1054 return;
1055 }
1056
1057 varCount = mExportVars.size();
1058 if (actualVarCount)
1059 *actualVarCount = varCount;
1060 if (varCount > maxVarCount)
1061 varCount = maxVarCount;
1062 if (vars) {
Logana4994f52010-11-27 14:06:02 +08001063 for (ExportVarList::const_iterator
1064 I = mExportVars.begin(), E = mExportVars.end(); I != E; I++) {
Logan1f028c02010-11-27 01:02:48 +08001065 *vars++ = *I;
1066 }
1067 }
Logan1f028c02010-11-27 01:02:48 +08001068}
1069
1070
1071// Interface for bccGetExportFuncs()
1072void Compiler::getExportFuncs(BCCsizei *actualFuncCount,
1073 BCCsizei maxFuncCount,
1074 BCCvoid **funcs) {
1075 int funcCount;
1076
1077 if (mUseCache && mCacheFd >= 0 && !mCacheNew) {
1078 funcCount = static_cast<int>(mCacheHdr->exportFuncsCount);
1079 if (actualFuncCount)
1080 *actualFuncCount = funcCount;
1081 if (funcCount > maxFuncCount)
1082 funcCount = maxFuncCount;
1083 if (funcs) {
1084 uint32_t *cachedFuncs = (uint32_t *)(mCacheMapAddr +
1085 mCacheHdr->exportFuncsOffset);
1086
1087 for (int i = 0; i < funcCount; i++) {
Logan7cc1baf2010-11-28 23:46:11 +08001088 *funcs = (BCCvoid *)((char *)(*cachedFuncs) + mCacheDiff);
1089 funcs++;
Logan1f028c02010-11-27 01:02:48 +08001090 cachedFuncs++;
1091 }
1092 }
1093 return;
1094 }
1095
1096 funcCount = mExportFuncs.size();
1097 if (actualFuncCount)
1098 *actualFuncCount = funcCount;
1099 if (funcCount > maxFuncCount)
1100 funcCount = maxFuncCount;
1101 if (funcs) {
Logan7cc1baf2010-11-28 23:46:11 +08001102 for (ExportFuncList::const_iterator
1103 I = mExportFuncs.begin(), E = mExportFuncs.end(); I != E; I++) {
Logan1f028c02010-11-27 01:02:48 +08001104 *funcs++ = *I;
1105 }
1106 }
Logan1f028c02010-11-27 01:02:48 +08001107}
1108
1109
1110// Interface for bccGetPragmas()
1111void Compiler::getPragmas(BCCsizei *actualStringCount,
1112 BCCsizei maxStringCount,
1113 BCCchar **strings) {
1114 int stringCount;
Logan7cc1baf2010-11-28 23:46:11 +08001115
Logan1f028c02010-11-27 01:02:48 +08001116 if (mUseCache && mCacheFd >= 0 && !mCacheNew) {
Logan7cc1baf2010-11-28 23:46:11 +08001117 stringCount = static_cast<int>(mCacheHdr->exportPragmasCount) * 2;
1118
Logan1f028c02010-11-27 01:02:48 +08001119 if (actualStringCount)
Logan7cc1baf2010-11-28 23:46:11 +08001120 *actualStringCount = stringCount;
1121
1122 if (stringCount > maxStringCount)
1123 stringCount = maxStringCount;
1124
1125 if (strings) {
1126 char *pragmaTab = mCacheMapAddr + mCacheHdr->exportPragmasOffset;
1127
1128 oBCCPragmaEntry *cachedPragmaEntries = (oBCCPragmaEntry *)pragmaTab;
1129
1130 for (int i = 0; stringCount >= 2; stringCount -= 2, i++) {
1131 *strings++ = pragmaTab + cachedPragmaEntries[i].pragmaNameOffset;
1132 *strings++ = pragmaTab + cachedPragmaEntries[i].pragmaValueOffset;
1133 }
1134 }
1135
Logan1f028c02010-11-27 01:02:48 +08001136 return;
1137 }
1138
1139 stringCount = mPragmas.size() * 2;
1140
1141 if (actualStringCount)
1142 *actualStringCount = stringCount;
1143 if (stringCount > maxStringCount)
1144 stringCount = maxStringCount;
1145 if (strings) {
Logan7cc1baf2010-11-28 23:46:11 +08001146 size_t i = 0;
Logan1f028c02010-11-27 01:02:48 +08001147 for (PragmaList::const_iterator it = mPragmas.begin();
Logan7cc1baf2010-11-28 23:46:11 +08001148 stringCount >= 2; stringCount -= 2, it++, ++i) {
Logan1f028c02010-11-27 01:02:48 +08001149 *strings++ = const_cast<BCCchar*>(it->first.c_str());
1150 *strings++ = const_cast<BCCchar*>(it->second.c_str());
1151 }
1152 }
1153
1154 return;
1155}
1156
1157
1158// Interface for bccGetFunctions()
1159void Compiler::getFunctions(BCCsizei *actualFunctionCount,
1160 BCCsizei maxFunctionCount,
1161 BCCchar **functions) {
1162 if (mCodeEmitter.get())
1163 mCodeEmitter->getFunctionNames(actualFunctionCount,
1164 maxFunctionCount,
1165 functions);
1166 else
1167 *actualFunctionCount = 0;
1168
1169 return;
1170}
1171
1172
1173// Interface for bccGetFunctionBinary()
1174void Compiler::getFunctionBinary(BCCchar *function,
1175 BCCvoid **base,
1176 BCCsizei *length) {
1177 if (mCodeEmitter.get()) {
1178 mCodeEmitter->getFunctionBinary(function, base, length);
1179 } else {
1180 *base = NULL;
1181 *length = 0;
1182 }
1183 return;
1184}
1185
1186
1187Compiler::~Compiler() {
1188 if (!mCodeMemMgr.get()) {
1189 // mCodeDataAddr and mCacheMapAddr are from loadCacheFile and not
1190 // managed by CodeMemoryManager.
1191
Loganeb3d12b2010-12-16 06:20:18 +08001192 if (mCodeDataAddr) {
1193 deallocateContext(mCodeDataAddr);
Logan1f028c02010-11-27 01:02:48 +08001194 }
1195
1196 if (mCacheMapAddr) {
1197 free(mCacheMapAddr);
1198 }
1199
1200 mCodeDataAddr = 0;
1201 mCacheMapAddr = 0;
1202 }
1203
1204 delete mModule;
Logan1f028c02010-11-27 01:02:48 +08001205 delete mContext;
Logana4994f52010-11-27 14:06:02 +08001206
1207 // llvm::llvm_shutdown();
Logan1f028c02010-11-27 01:02:48 +08001208}
1209
1210
1211// Design of caching EXE:
1212// ======================
1213// 1. Each process will have virtual address available starting at 0x7e00000.
1214// E.g., Books and Youtube all have its own 0x7e00000. Next, we should
1215// minimize the chance of needing to do relocation INSIDE an app too.
1216//
1217// 2. Each process will have ONE class static variable called BccCodeAddr.
1218// I.e., even though the Compiler class will have multiple Compiler objects,
1219// e.g, one object for carousel.rs and the other for pageturn.rs,
1220// both Compiler objects will share 1 static variable called BccCodeAddr.
1221//
1222// Key observation: Every app (process) initiates, say 3, scripts (which
1223// correspond to 3 Compiler objects) in the same order, usually.
1224//
1225// So, we should mmap to, e.g., 0x7e00000, 0x7e40000, 0x7e80000 for the 3
1226// scripts, respectively. Each time, BccCodeAddr should be updated after
1227// JITTing a script. BTW, in ~Compiler(), BccCodeAddr should NOT be
1228// decremented back by CodeDataSize. I.e., for 3 scripts: A, B, C,
1229// even if it's A -> B -> ~B -> C -> ~C -> B -> C ... no relocation will
1230// ever be needed.)
1231//
1232// If we are lucky, then we don't need relocation ever, since next time the
1233// application gets run, the 3 scripts are likely created in the SAME order.
1234//
1235//
1236// End-to-end algorithm on when to caching and when to JIT:
1237// ========================================================
1238// Prologue:
1239// ---------
1240// Assertion: bccReadBC() is always called and is before bccCompileBC(),
1241// bccLoadBinary(), ...
1242//
1243// Key variable definitions: Normally,
1244// Compiler::BccCodeAddr: non-zero if (USE_CACHE)
1245// | (Stricter, because currently relocation doesn't work. So mUseCache only
1246// | when BccCodeAddr is nonzero.)
1247// V
1248// mUseCache: In addition to (USE_CACHE), resName is non-zero
1249// Note: mUseCache will be set to false later on whenever we find that caching
1250// won't work. E.g., when mCodeDataAddr != mCacheHdr->cachedCodeDataAddr.
1251// This is because currently relocation doesn't work.
1252// | (Stricter, initially)
1253// V
1254// mCacheFd: In addition, >= 0 if openCacheFile() returns >= 0
1255// | (Stricter)
1256// V
1257// mCacheNew: In addition, mCacheFd's size is 0, so need to call genCacheFile()
1258// at the end of compile()
1259//
1260//
1261// Main algorithm:
1262// ---------------
1263// #if !USE_RELOCATE
1264// Case 1. ReadBC() doesn't detect a cache file:
1265// compile(), which calls genCacheFile() at the end.
1266// Note: mCacheNew will guard the invocation of genCacheFile()
1267// Case 2. ReadBC() find a cache file
1268// loadCacheFile(). But if loadCacheFile() failed, should go to Case 1.
1269// #endif
1270
1271// Note: loadCacheFile() and genCacheFile() go hand in hand
1272void Compiler::genCacheFile() {
1273 if (lseek(mCacheFd, 0, SEEK_SET) != 0) {
1274 LOGE("Unable to seek to 0: %s\n", strerror(errno));
1275 return;
1276 }
1277
1278 bool codeOffsetNeedPadding = false;
1279
1280 uint32_t offset = sizeof(oBCCHeader);
1281
1282 // BCC Cache File Header
1283 oBCCHeader *hdr = (oBCCHeader *)malloc(sizeof(oBCCHeader));
1284
1285 if (!hdr) {
1286 LOGE("Unable to allocate oBCCHeader.\n");
1287 return;
1288 }
1289
1290 // Magic Words
1291 memcpy(hdr->magic, OBCC_MAGIC, 4);
1292 memcpy(hdr->magicVersion, OBCC_MAGIC_VERS, 4);
1293
1294 // Timestamp
Shih-wei Liaodb69c552010-12-07 01:37:48 -08001295 // TODO(sliao): Should be .bc's ModifyTime. Now just use it to store
1296 // threadable
1297 hdr->sourceWhen = (uint32_t) mCodeEmitter->mpSymbolLookupFn(
1298 mpSymbolLookupContext,
1299 "__isThreadable");
1300
1301 hdr->rslibWhen = 0; // TODO(sliao)
Logan9d94f162010-12-07 12:39:25 +08001302 hdr->libRSWhen = statModifyTime(libRSPath);
1303 hdr->libbccWhen = statModifyTime(libBccPath);
Logan1f028c02010-11-27 01:02:48 +08001304
1305 // Current Memory Address (Saved for Recalculation)
1306 hdr->cachedCodeDataAddr = reinterpret_cast<uint32_t>(mCodeDataAddr);
1307 hdr->rootAddr = reinterpret_cast<uint32_t>(lookup("root"));
1308 hdr->initAddr = reinterpret_cast<uint32_t>(lookup("init"));
1309
1310 // Relocation Table Offset and Entry Count
1311 hdr->relocOffset = sizeof(oBCCHeader);
1312 hdr->relocCount = mCodeEmitter->getCachingRelocations().size();
1313
Logan7cc1baf2010-11-28 23:46:11 +08001314 offset += hdr->relocCount * sizeof(oBCCRelocEntry);
Logan1f028c02010-11-27 01:02:48 +08001315
1316 // Export Variable Table Offset and Entry Count
1317 hdr->exportVarsOffset = offset;
1318 hdr->exportVarsCount = mExportVars.size();
1319
1320 offset += hdr->exportVarsCount * sizeof(uint32_t);
1321
1322 // Export Function Table Offset and Entry Count
1323 hdr->exportFuncsOffset = offset;
1324 hdr->exportFuncsCount = mExportFuncs.size();
1325
1326 offset += hdr->exportFuncsCount * sizeof(uint32_t);
1327
1328 // Export Pragmas Table Offset and Entry Count
1329 hdr->exportPragmasOffset = offset;
Logan7cc1baf2010-11-28 23:46:11 +08001330 hdr->exportPragmasCount = mPragmas.size();
1331 hdr->exportPragmasSize = hdr->exportPragmasCount * sizeof(oBCCPragmaEntry);
Logan1f028c02010-11-27 01:02:48 +08001332
Logan7cc1baf2010-11-28 23:46:11 +08001333 offset += hdr->exportPragmasCount * sizeof(oBCCPragmaEntry);
1334
1335 for (PragmaList::const_iterator
1336 I = mPragmas.begin(), E = mPragmas.end(); I != E; ++I) {
1337 offset += I->first.size() + 1;
1338 offset += I->second.size() + 1;
1339 hdr->exportPragmasSize += I->first.size() + I->second.size() + 2;
1340 }
Logan1f028c02010-11-27 01:02:48 +08001341
1342 // Code Offset and Size
1343
1344 { // Always pad to the page boundary for now
1345 long pagesize = sysconf(_SC_PAGESIZE);
1346
1347 if (offset % pagesize > 0) {
1348 codeOffsetNeedPadding = true;
1349 offset += pagesize - (offset % pagesize);
1350 }
1351 }
1352
1353 hdr->codeOffset = offset;
1354 hdr->codeSize = MaxCodeSize;
1355
1356 offset += hdr->codeSize;
1357
1358 // Data (Global Variable) Offset and Size
1359 hdr->dataOffset = offset;
1360 hdr->dataSize = MaxGlobalVarSize;
1361
1362 offset += hdr->dataSize;
1363
1364 // Checksum
1365#if 1
1366 {
1367 // Note: This is an simple checksum implementation that are using xor
1368 // to calculate even parity (for code and data only).
1369
1370 uint32_t sum = 0;
1371 uint32_t *ptr = (uint32_t *)mCodeDataAddr;
1372
Loganeb3d12b2010-12-16 06:20:18 +08001373 for (size_t i = 0; i < BCC_CONTEXT_SIZE / sizeof(uint32_t); ++i) {
Logan1f028c02010-11-27 01:02:48 +08001374 sum ^= *ptr++;
1375 }
1376
1377 hdr->checksum = sum;
1378 }
1379#else
1380 hdr->checksum = 0; // Set Field checksum. TODO(all)
1381#endif
1382
1383 // Write Header
1384 sysWriteFully(mCacheFd, reinterpret_cast<char const *>(hdr),
1385 sizeof(oBCCHeader), "Write oBCC header");
1386
1387 // Write Relocation Entry Table
1388 {
1389 size_t allocSize = hdr->relocCount * sizeof(oBCCRelocEntry);
1390
1391 oBCCRelocEntry const*records = &mCodeEmitter->getCachingRelocations()[0];
1392
1393 sysWriteFully(mCacheFd, reinterpret_cast<char const *>(records),
1394 allocSize, "Write Relocation Entries");
1395 }
1396
1397 // Write Export Variables Table
1398 {
1399 uint32_t *record, *ptr;
1400
1401 record = (uint32_t *)calloc(hdr->exportVarsCount, sizeof(uint32_t));
1402 ptr = record;
1403
1404 if (!record) {
1405 goto bail;
1406 }
1407
1408 for (ExportVarList::const_iterator I = mExportVars.begin(),
1409 E = mExportVars.end(); I != E; I++) {
1410 *ptr++ = reinterpret_cast<uint32_t>(*I);
1411 }
1412
1413 sysWriteFully(mCacheFd, reinterpret_cast<char const *>(record),
1414 hdr->exportVarsCount * sizeof(uint32_t),
1415 "Write ExportVars");
1416
1417 free(record);
1418 }
1419
1420 // Write Export Functions Table
1421 {
1422 uint32_t *record, *ptr;
1423
1424 record = (uint32_t *)calloc(hdr->exportFuncsCount, sizeof(uint32_t));
1425 ptr = record;
1426
1427 if (!record) {
1428 goto bail;
1429 }
1430
1431 for (ExportFuncList::const_iterator I = mExportFuncs.begin(),
1432 E = mExportFuncs.end(); I != E; I++) {
1433 *ptr++ = reinterpret_cast<uint32_t>(*I);
1434 }
1435
1436 sysWriteFully(mCacheFd, reinterpret_cast<char const *>(record),
1437 hdr->exportFuncsCount * sizeof(uint32_t),
1438 "Write ExportFuncs");
1439
1440 free(record);
1441 }
1442
1443
Logan7cc1baf2010-11-28 23:46:11 +08001444 // Write Export Pragmas Table
1445 {
1446 uint32_t pragmaEntryOffset =
1447 hdr->exportPragmasCount * sizeof(oBCCPragmaEntry);
Logan1f028c02010-11-27 01:02:48 +08001448
Logan7cc1baf2010-11-28 23:46:11 +08001449 for (PragmaList::const_iterator
1450 I = mPragmas.begin(), E = mPragmas.end(); I != E; ++I) {
1451 oBCCPragmaEntry entry;
1452
1453 entry.pragmaNameOffset = pragmaEntryOffset;
1454 entry.pragmaNameSize = I->first.size();
1455 pragmaEntryOffset += entry.pragmaNameSize + 1;
1456
1457 entry.pragmaValueOffset = pragmaEntryOffset;
1458 entry.pragmaValueSize = I->second.size();
1459 pragmaEntryOffset += entry.pragmaValueSize + 1;
1460
1461 sysWriteFully(mCacheFd, (char *)&entry, sizeof(oBCCPragmaEntry),
1462 "Write export pragma entry");
1463 }
1464
1465 for (PragmaList::const_iterator
1466 I = mPragmas.begin(), E = mPragmas.end(); I != E; ++I) {
1467 sysWriteFully(mCacheFd, I->first.c_str(), I->first.size() + 1,
1468 "Write export pragma name string");
1469 sysWriteFully(mCacheFd, I->second.c_str(), I->second.size() + 1,
1470 "Write export pragma value string");
1471 }
1472 }
Logan1f028c02010-11-27 01:02:48 +08001473
1474 if (codeOffsetNeedPadding) {
1475 // requires additional padding
1476 lseek(mCacheFd, hdr->codeOffset, SEEK_SET);
1477 }
1478
1479 // Write Generated Code and Global Variable
1480 sysWriteFully(mCacheFd, mCodeDataAddr, MaxCodeSize + MaxGlobalVarSize,
1481 "Write code and global variable");
1482
1483 goto close_return;
1484
1485bail:
1486 if (ftruncate(mCacheFd, 0) != 0) {
1487 LOGW("Warning: unable to truncate cache file: %s\n", strerror(errno));
1488 }
1489
1490close_return:
1491 free(hdr);
1492 close(mCacheFd);
1493 mCacheFd = -1;
1494}
1495
1496
1497// OpenCacheFile() returns fd of the cache file.
1498// Input:
1499// BCCchar *resName: Used to genCacheFileName()
1500// bool createIfMissing: If false, turn off caching
1501// Output:
1502// returns fd: If -1: Failed
1503// mCacheNew: If true, the returned fd is new. Otherwise, the fd is the
1504// cache file's file descriptor
1505// Note: openCacheFile() will check the cache file's validity,
1506// such as Magic number, sourceWhen... dependencies.
Shih-wei Liaoe6a18512010-12-09 12:38:10 -08001507int Compiler::openCacheFile(const BCCchar *resName,
1508 const BCCchar *cacheDir,
1509 bool createIfMissing) {
Logan1f028c02010-11-27 01:02:48 +08001510 int fd, cc;
1511 struct stat fdStat, fileStat;
1512 bool readOnly = false;
1513
Shih-wei Liaoe6a18512010-12-09 12:38:10 -08001514 char *cacheFileName = genCacheFileName(cacheDir, resName, ".oBCC");
Logan1f028c02010-11-27 01:02:48 +08001515
1516 mCacheNew = false;
1517
1518retry:
1519 /*
1520 * Try to open the cache file. If we've been asked to,
1521 * create it if it doesn't exist.
1522 */
1523 fd = createIfMissing ? open(cacheFileName, O_CREAT|O_RDWR, 0644) : -1;
1524 if (fd < 0) {
1525 fd = open(cacheFileName, O_RDONLY, 0);
1526 if (fd < 0) {
1527 if (createIfMissing) {
1528 LOGW("Can't open bcc-cache '%s': %s\n",
1529 cacheFileName, strerror(errno));
1530 mUseCache = false;
1531 }
1532 return fd;
1533 }
1534 readOnly = true;
1535 }
1536
1537 /*
1538 * Grab an exclusive lock on the cache file. If somebody else is
1539 * working on it, we'll block here until they complete.
1540 */
1541 LOGV("bcc: locking cache file %s (fd=%d, boot=%d)\n",
1542 cacheFileName, fd);
1543
1544 cc = flock(fd, LOCK_EX | LOCK_NB);
1545 if (cc != 0) {
1546 LOGD("bcc: sleeping on flock(%s)\n", cacheFileName);
1547 cc = flock(fd, LOCK_EX);
1548 }
1549
1550 if (cc != 0) {
1551 LOGE("Can't lock bcc cache '%s': %d\n", cacheFileName, cc);
1552 close(fd);
1553 return -1;
1554 }
1555 LOGV("bcc: locked cache file\n");
1556
1557 /*
1558 * Check to see if the fd we opened and locked matches the file in
1559 * the filesystem. If they don't, then somebody else unlinked ours
1560 * and created a new file, and we need to use that one instead. (If
1561 * we caught them between the unlink and the create, we'll get an
1562 * ENOENT from the file stat.)
1563 */
1564 cc = fstat(fd, &fdStat);
1565 if (cc != 0) {
1566 LOGE("Can't stat open file '%s'\n", cacheFileName);
1567 LOGV("bcc: unlocking cache file %s\n", cacheFileName);
1568 goto close_fail;
1569 }
1570 cc = stat(cacheFileName, &fileStat);
1571 if (cc != 0 ||
1572 fdStat.st_dev != fileStat.st_dev || fdStat.st_ino != fileStat.st_ino) {
1573 LOGD("bcc: our open cache file is stale; sleeping and retrying\n");
1574 LOGV("bcc: unlocking cache file %s\n", cacheFileName);
1575 flock(fd, LOCK_UN);
1576 close(fd);
1577 usleep(250 * 1000); // if something is hosed, don't peg machine
1578 goto retry;
1579 }
1580
1581 /*
1582 * We have the correct file open and locked. If the file size is zero,
1583 * then it was just created by us, and we want to fill in some fields
1584 * in the "bcc" header and set "mCacheNew". Otherwise, we want to
1585 * verify that the fields in the header match our expectations, and
1586 * reset the file if they don't.
1587 */
1588 if (fdStat.st_size == 0) {
1589 if (readOnly) { // The device is readOnly --> close_fail
1590 LOGW("bcc: file has zero length and isn't writable\n");
1591 goto close_fail;
1592 }
1593 /*cc = createEmptyHeader(fd);
1594 if (cc != 0)
1595 goto close_fail;
1596 */
1597 mCacheNew = true;
1598 LOGV("bcc: successfully initialized new cache file\n");
1599 } else {
1600 // Calculate sourceWhen
1601 // XXX
1602 uint32_t sourceWhen = 0;
1603 uint32_t rslibWhen = 0;
Logan9d94f162010-12-07 12:39:25 +08001604 uint32_t libRSWhen = statModifyTime(libRSPath);
1605 uint32_t libbccWhen = statModifyTime(libBccPath);
Logan1f028c02010-11-27 01:02:48 +08001606 if (!checkHeaderAndDependencies(fd,
1607 sourceWhen,
1608 rslibWhen,
1609 libRSWhen,
1610 libbccWhen)) {
1611 // If checkHeaderAndDependencies returns 0: FAILED
1612 // Will truncate the file and retry to createIfMissing the file
1613
1614 if (readOnly) { // Shouldn't be readonly.
1615 /*
1616 * We could unlink and rewrite the file if we own it or
1617 * the "sticky" bit isn't set on the directory. However,
1618 * we're not able to truncate it, which spoils things. So,
1619 * give up now.
1620 */
1621 if (createIfMissing) {
1622 LOGW("Cached file %s is stale and not writable\n",
1623 cacheFileName);
1624 }
1625 goto close_fail;
1626 }
1627
1628 /*
1629 * If we truncate the existing file before unlinking it, any
1630 * process that has it mapped will fail when it tries to touch
1631 * the pages? Probably OK because we use MAP_PRIVATE.
1632 */
1633 LOGD("oBCC file is stale or bad; removing and retrying (%s)\n",
1634 cacheFileName);
1635 if (ftruncate(fd, 0) != 0) {
1636 LOGW("Warning: unable to truncate cache file '%s': %s\n",
1637 cacheFileName, strerror(errno));
1638 /* keep going */
1639 }
1640 if (unlink(cacheFileName) != 0) {
1641 LOGW("Warning: unable to remove cache file '%s': %d %s\n",
1642 cacheFileName, errno, strerror(errno));
1643 /* keep going; permission failure should probably be fatal */
1644 }
1645 LOGV("bcc: unlocking cache file %s\n", cacheFileName);
1646 flock(fd, LOCK_UN);
1647 close(fd);
1648 goto retry;
1649 } else {
1650 // Got cacheFile! Good to go.
1651 LOGV("Good cache file\n");
1652 }
1653 }
1654
1655 assert(fd >= 0);
1656 return fd;
1657
1658close_fail:
1659 flock(fd, LOCK_UN);
1660 close(fd);
1661 return -1;
1662} // End of openCacheFile()
1663
Shih-wei Liaoe6a18512010-12-09 12:38:10 -08001664// Input: cacheDir
1665// Input: resName
1666// Input: extName
1667//
1668// Note: cacheFile = resName + extName
1669//
1670// Output: Returns cachePath == cacheDir + cacheFile
1671char *Compiler::genCacheFileName(const char *cacheDir,
1672 const char *resName,
1673 const char *extName) {
1674 char cachePath[512];
1675 char cacheFile[sizeof(cachePath)];
1676 const size_t kBufLen = sizeof(cachePath) - 1;
Logan1f028c02010-11-27 01:02:48 +08001677
Shih-wei Liaoe6a18512010-12-09 12:38:10 -08001678 cacheFile[0] = '\0';
1679 // Note: resName today is usually something like
1680 // "/com.android.fountain:raw/fountain"
1681 if (resName[0] != '/') {
1682 // Get the absolute path of the raw/***.bc file.
1683
1684 // Generate the absolute path. This doesn't do everything it
1685 // should, e.g. if resName is "./out/whatever" it doesn't crunch
1686 // the leading "./" out because this if-block is not triggered,
1687 // but it'll make do.
1688 //
1689 if (getcwd(cacheFile, kBufLen) == NULL) {
Logan1f028c02010-11-27 01:02:48 +08001690 LOGE("Can't get CWD while opening raw/***.bc file\n");
1691 return NULL;
1692 }
Shih-wei Liaoe6a18512010-12-09 12:38:10 -08001693 // Append "/" at the end of cacheFile so far.
1694 strncat(cacheFile, "/", kBufLen);
1695 }
1696
1697 // cacheFile = resName + extName
1698 //
1699 strncat(cacheFile, resName, kBufLen);
1700 if (extName != NULL) {
Logan1f028c02010-11-27 01:02:48 +08001701 // TODO(srhines): strncat() is a bit dangerous
Shih-wei Liaoe6a18512010-12-09 12:38:10 -08001702 strncat(cacheFile, extName, kBufLen);
Logan1f028c02010-11-27 01:02:48 +08001703 }
1704
Shih-wei Liaoe6a18512010-12-09 12:38:10 -08001705 // Turn the path into a flat filename by replacing
1706 // any slashes after the first one with '@' characters.
1707 char *cp = cacheFile + 1;
Logan1f028c02010-11-27 01:02:48 +08001708 while (*cp != '\0') {
1709 if (*cp == '/') {
1710 *cp = '@';
1711 }
1712 cp++;
1713 }
1714
Shih-wei Liaoe6a18512010-12-09 12:38:10 -08001715 // Tack on the file name for the actual cache file path.
1716 strncpy(cachePath, cacheDir, kBufLen);
1717 strncat(cachePath, cacheFile, kBufLen);
Logan1f028c02010-11-27 01:02:48 +08001718
Shih-wei Liaoe6a18512010-12-09 12:38:10 -08001719 LOGV("Cache file for '%s' '%s' is '%s'\n", resName, extName, cachePath);
1720 return strdup(cachePath);
Logan1f028c02010-11-27 01:02:48 +08001721}
1722
1723/*
1724 * Read the oBCC header, verify it, then read the dependent section
1725 * and verify that data as well.
1726 *
1727 * On successful return, the file will be seeked immediately past the
1728 * oBCC header.
1729 */
1730bool Compiler::checkHeaderAndDependencies(int fd,
1731 uint32_t sourceWhen,
1732 uint32_t rslibWhen,
1733 uint32_t libRSWhen,
1734 uint32_t libbccWhen) {
1735 ssize_t actual;
1736 oBCCHeader optHdr;
1737 uint32_t val;
1738 uint8_t const *magic, *magicVer;
1739
1740 /*
1741 * Start at the start. The "bcc" header, when present, will always be
1742 * the first thing in the file.
1743 */
1744 if (lseek(fd, 0, SEEK_SET) != 0) {
1745 LOGE("bcc: failed to seek to start of file: %s\n", strerror(errno));
1746 goto bail;
1747 }
1748
1749 /*
1750 * Read and do trivial verification on the bcc header. The header is
1751 * always in host byte order.
1752 */
1753 actual = read(fd, &optHdr, sizeof(optHdr));
1754 if (actual < 0) {
1755 LOGE("bcc: failed reading bcc header: %s\n", strerror(errno));
1756 goto bail;
1757 } else if (actual != sizeof(optHdr)) {
1758 LOGE("bcc: failed reading bcc header (got %d of %zd)\n",
1759 (int) actual, sizeof(optHdr));
1760 goto bail;
1761 }
1762
1763 magic = optHdr.magic;
1764 if (memcmp(magic, OBCC_MAGIC, 4) != 0) {
1765 /* not an oBCC file, or previous attempt was interrupted */
1766 LOGD("bcc: incorrect opt magic number (0x%02x %02x %02x %02x)\n",
1767 magic[0], magic[1], magic[2], magic[3]);
1768 goto bail;
1769 }
1770
1771 magicVer = optHdr.magicVersion;
Logancd045f92010-12-06 19:04:53 +08001772 if (memcmp(magicVer, OBCC_MAGIC_VERS, 4) != 0) {
Logan1f028c02010-11-27 01:02:48 +08001773 LOGW("bcc: stale oBCC version (0x%02x %02x %02x %02x)\n",
1774 magicVer[0], magicVer[1], magicVer[2], magicVer[3]);
1775 goto bail;
1776 }
1777
1778 /*
1779 * Do the header flags match up with what we want?
1780 *
1781 * This is useful because it allows us to automatically regenerate
1782 * a file when settings change (e.g. verification is now mandatory),
1783 * but can cause difficulties if the thing we depend upon
1784 * were handled differently than the current options specify.
1785 *
1786 * So, for now, we essentially ignore "expectVerify" and "expectOpt"
1787 * by limiting the match mask.
1788 *
1789 * The only thing we really can't handle is incorrect byte-ordering.
1790 */
1791
1792 val = optHdr.sourceWhen;
Shih-wei Liaodb69c552010-12-07 01:37:48 -08001793 // TODO(sliao): Shouldn't overload sourceWhen in the future.
1794 if (!val) {
1795 mpSymbolLookupFn(mpSymbolLookupContext, "__clearThreadable");
Logan1f028c02010-11-27 01:02:48 +08001796 }
Shih-wei Liaodb69c552010-12-07 01:37:48 -08001797 // if (val && (val != sourceWhen)) {
1798 // LOGI("bcc: source file mod time mismatch (%08x vs %08x)\n",
1799 // val, sourceWhen);
1800 // goto bail;
1801 // }
1802
Logan1f028c02010-11-27 01:02:48 +08001803 val = optHdr.rslibWhen;
1804 if (val && (val != rslibWhen)) {
1805 LOGI("bcc: rslib file mod time mismatch (%08x vs %08x)\n",
1806 val, rslibWhen);
1807 goto bail;
1808 }
1809 val = optHdr.libRSWhen;
1810 if (val && (val != libRSWhen)) {
1811 LOGI("bcc: libRS file mod time mismatch (%08x vs %08x)\n",
1812 val, libRSWhen);
1813 goto bail;
1814 }
1815 val = optHdr.libbccWhen;
1816 if (val && (val != libbccWhen)) {
1817 LOGI("bcc: libbcc file mod time mismatch (%08x vs %08x)\n",
1818 val, libbccWhen);
1819 goto bail;
1820 }
1821
1822 return true;
1823
1824bail:
1825 return false;
1826}
1827
1828} // namespace bcc