BitcodeTranslator.cpp revision c7d67a701663191bcdab2416c11b69fae16d49fb
1/*
2 * Copyright 2011, 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#include "bcinfo/BitcodeTranslator.h"
18
19#include "BitReader_2_7/BitReader_2_7.h"
20#include "BitReader_3_0/BitReader_3_0.h"
21
22#define LOG_TAG "bcinfo"
23#include <cutils/log.h>
24
25#include "llvm/ADT/OwningPtr.h"
26#include "llvm/Bitcode/BitstreamWriter.h"
27#include "llvm/Bitcode/ReaderWriter.h"
28#include "llvm/LLVMContext.h"
29#include "llvm/Module.h"
30#include "llvm/Support/MemoryBuffer.h"
31
32#include <cstdlib>
33
34namespace bcinfo {
35
36/**
37 * Define minimum and maximum target API versions. These correspond to the
38 * same API levels used by the standard Android SDK.
39 *
40 * LLVM 2.7
41 *  11 - Honeycomb
42 *  12 - Honeycomb MR1
43 *  13 - Honeycomb MR2
44 *
45 * LLVM 3.0
46 *  14 - Ice Cream Sandwich
47 *  15 - Ice Cream Sandwich MR1
48 *
49 * LLVM 3.1
50 *  16 - Ice Cream Sandwich MR2
51 */
52static const unsigned int kMinimumAPIVersion = 11;
53static const unsigned int kMaximumAPIVersion = BCINFO_API_VERSION;
54static const unsigned int kCurrentAPIVersion = 10000;
55
56/**
57 * The minimum version which does not require translation (i.e. is already
58 * compatible with LLVM's default bitcode reader).
59 */
60static const unsigned int kMinimumUntranslatedVersion = 16;
61static const unsigned int kMinimumCompatibleVersion_LLVM_3_0 = 14;
62static const unsigned int kMinimumCompatibleVersion_LLVM_2_7 = 11;
63
64
65BitcodeTranslator::BitcodeTranslator(const char *bitcode, size_t bitcodeSize,
66                                     unsigned int version)
67    : mBitcode(bitcode), mBitcodeSize(bitcodeSize), mTranslatedBitcode(NULL),
68      mTranslatedBitcodeSize(0), mVersion(version) {
69  return;
70}
71
72
73BitcodeTranslator::~BitcodeTranslator() {
74  if (mVersion < kMinimumUntranslatedVersion) {
75    // We didn't actually do a translation in the alternate case, so deleting
76    // the bitcode would be improper.
77    delete [] mTranslatedBitcode;
78  }
79  mTranslatedBitcode = NULL;
80  return;
81}
82
83
84bool BitcodeTranslator::translate() {
85  if (!mBitcode || !mBitcodeSize) {
86    LOGE("Invalid/empty bitcode");
87    return false;
88  }
89
90  if ((mVersion != kCurrentAPIVersion) &&
91      ((mVersion < kMinimumAPIVersion) ||
92       (mVersion > kMaximumAPIVersion))) {
93    LOGE("Invalid API version: %u is out of range ('%u' - '%u')", mVersion,
94         kMinimumAPIVersion, kMaximumAPIVersion);
95    return false;
96  }
97
98  // We currently don't need to transcode any API version higher than 14 or
99  // the current API version (i.e. 10000)
100  if (mVersion >= kMinimumUntranslatedVersion) {
101    mTranslatedBitcode = mBitcode;
102    mTranslatedBitcodeSize = mBitcodeSize;
103    return true;
104  }
105
106  // Do the actual transcoding by invoking a 2.7-era bitcode reader that can
107  // then write the bitcode back out in a more modern (acceptable) version.
108  llvm::OwningPtr<llvm::LLVMContext> mContext(new llvm::LLVMContext());
109  llvm::OwningPtr<llvm::MemoryBuffer> MEM(
110    llvm::MemoryBuffer::getMemBuffer(
111      llvm::StringRef(mBitcode, mBitcodeSize)));
112  std::string error;
113
114  // Module ownership is handled by the context, so we don't need to free it.
115  llvm::Module *module = NULL;
116
117  if (mVersion >= kMinimumCompatibleVersion_LLVM_3_0) {
118    module = llvm_3_0::ParseBitcodeFile(MEM.get(), *mContext, &error);
119  } else if (mVersion >= kMinimumCompatibleVersion_LLVM_2_7) {
120    module = llvm_2_7::ParseBitcodeFile(MEM.get(), *mContext, &error);
121  } else {
122    LOGE("No compatible bitcode reader for API version %d", mVersion);
123    return false;
124  }
125
126  if (!module) {
127    LOGE("Could not parse bitcode file");
128    LOGE("%s", error.c_str());
129    return false;
130  }
131
132  std::vector<unsigned char> Buffer;
133  llvm::BitstreamWriter Stream(Buffer);
134  Buffer.reserve(mBitcodeSize);
135  llvm::WriteBitcodeToStream(module, Stream);
136
137  char *c = new char[Buffer.size()];
138  memcpy(c, &Buffer.front(), Buffer.size());
139
140  mTranslatedBitcode = c;
141  mTranslatedBitcodeSize = Buffer.size();
142
143  return true;
144}
145
146}  // namespace bcinfo
147
148