MCCacheWriter.cpp revision 2ca6e576421e86e0128991b825c238f1d4221910
1/*
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#include "MCCacheWriter.h"
18
19#include "ContextManager.h"
20#include "DebugHelper.h"
21#include "FileHandle.h"
22#include "Script.h"
23
24#include <map>
25#include <string>
26#include <vector>
27#include <utility>
28
29#include <stdint.h>
30#include <stdlib.h>
31#include <string.h>
32
33using namespace std;
34
35#if USE_MCJIT
36namespace bcc {
37
38MCCacheWriter::~MCCacheWriter() {
39#define CHECK_AND_FREE(VAR) if (VAR) { free(VAR); }
40
41  CHECK_AND_FREE(mpHeaderSection);
42  CHECK_AND_FREE(mpStringPoolSection);
43  CHECK_AND_FREE(mpDependencyTableSection);
44  CHECK_AND_FREE(mpExportVarListSection);
45  CHECK_AND_FREE(mpExportFuncListSection);
46  CHECK_AND_FREE(mpPragmaListSection);
47  CHECK_AND_FREE(mpObjectSlotSection);
48
49#undef CHECK_AND_FREE
50}
51
52bool MCCacheWriter::writeCacheFile(FileHandle *objFile, FileHandle *infoFile,
53                                 Script *S, uint32_t libRS_threadable) {
54  if (!objFile || objFile->getFD() < 0 || !infoFile || infoFile->getFD() < 0) {
55    return false;
56  }
57
58  mObjFile = objFile;
59  mInfoFile = infoFile;
60  mpOwner = S;
61
62  bool result = prepareHeader(libRS_threadable)
63             && prepareDependencyTable()
64             && preparePragmaList()
65             && prepareStringPool()
66             && prepareExportVarList()
67             && prepareExportFuncList()
68             && prepareObjectSlotList()
69             && calcSectionOffset()
70             && writeAll()
71             ;
72
73  return result;
74}
75
76
77bool MCCacheWriter::prepareHeader(uint32_t libRS_threadable) {
78  MCO_Header *header = (MCO_Header *)malloc(sizeof(MCO_Header));
79
80  if (!header) {
81    LOGE("Unable to allocate for header.\n");
82    return false;
83  }
84
85  mpHeaderSection = header;
86
87  // Initialize
88  memset(header, '\0', sizeof(MCO_Header));
89
90  // Magic word and version
91  memcpy(header->magic, OBCC_MAGIC, 4);
92  memcpy(header->version, OBCC_VERSION, 4);
93
94  // Machine Integer Type
95  uint32_t number = 0x00000001;
96  header->endianness = (*reinterpret_cast<char *>(&number) == 1) ? 'e' : 'E';
97  header->sizeof_off_t = sizeof(off_t);
98  header->sizeof_size_t = sizeof(size_t);
99  header->sizeof_ptr_t = sizeof(void *);
100
101  header->root_base_addr = mpOwner->lookup("root");
102
103  LOGD("Lookup root() address [%p]", header->root_base_addr);
104
105  // libRS is threadable dirty hack
106  // TODO: This should be removed in the future
107  header->libRS_threadable = libRS_threadable;
108
109  return true;
110}
111
112
113bool MCCacheWriter::prepareDependencyTable() {
114  size_t tableSize = sizeof(OBCC_DependencyTable) +
115                     sizeof(OBCC_Dependency) * mDependencies.size();
116
117  OBCC_DependencyTable *tab = (OBCC_DependencyTable *)malloc(tableSize);
118
119  if (!tab) {
120    LOGE("Unable to allocate for dependency table section.\n");
121    return false;
122  }
123
124  mpDependencyTableSection = tab;
125  mpHeaderSection->depend_tab_size = tableSize;
126
127  tab->count = mDependencies.size();
128
129  size_t i = 0;
130  for (map<string, pair<uint32_t, unsigned char const *> >::iterator
131       I = mDependencies.begin(), E = mDependencies.end(); I != E; ++I, ++i) {
132    OBCC_Dependency *dep = &tab->table[i];
133
134    dep->res_name_strp_index = addString(I->first.c_str(), I->first.size());
135    dep->res_type = I->second.first;
136    memcpy(dep->sha1, I->second.second, 20);
137  }
138
139  return true;
140}
141
142bool MCCacheWriter::preparePragmaList() {
143  size_t pragmaCount = mpOwner->getPragmaCount();
144
145  size_t listSize = sizeof(OBCC_PragmaList) +
146                    sizeof(OBCC_Pragma) * pragmaCount;
147
148  OBCC_PragmaList *list = (OBCC_PragmaList *)malloc(listSize);
149
150  if (!list) {
151    LOGE("Unable to allocate for pragma list\n");
152    return false;
153  }
154
155  mpPragmaListSection = list;
156  mpHeaderSection->pragma_list_size = listSize;
157
158  list->count = pragmaCount;
159
160  vector<char const *> keyList(pragmaCount);
161  vector<char const *> valueList(pragmaCount);
162  mpOwner->getPragmaList(pragmaCount, &*keyList.begin(), &*valueList.begin());
163
164  for (size_t i = 0; i < pragmaCount; ++i) {
165    char const *key = keyList[i];
166    char const *value = valueList[i];
167
168    size_t keyLen = strlen(key);
169    size_t valueLen = strlen(value);
170
171    OBCC_Pragma *pragma = &list->list[i];
172    pragma->key_strp_index = addString(key, keyLen);
173    pragma->value_strp_index = addString(value, valueLen);
174  }
175
176  return true;
177}
178
179bool MCCacheWriter::prepareStringPool() {
180  // Calculate string pool size
181  size_t size = sizeof(OBCC_StringPool) +
182                sizeof(OBCC_String) * mStringPool.size();
183
184  off_t strOffset = size;
185
186  for (size_t i = 0; i < mStringPool.size(); ++i) {
187    size += mStringPool[i].second + 1;
188  }
189
190  // Create string pool
191  OBCC_StringPool *pool = (OBCC_StringPool *)malloc(size);
192
193  if (!pool) {
194    LOGE("Unable to allocate string pool.\n");
195    return false;
196  }
197
198  mpStringPoolSection = pool;
199  mpHeaderSection->str_pool_size = size;
200
201  pool->count = mStringPool.size();
202
203  char *strPtr = reinterpret_cast<char *>(pool) + strOffset;
204
205  for (size_t i = 0; i < mStringPool.size(); ++i) {
206    OBCC_String *str = &pool->list[i];
207
208    str->length = mStringPool[i].second;
209    str->offset = strOffset;
210    memcpy(strPtr, mStringPool[i].first, str->length);
211
212    strPtr += str->length;
213    *strPtr++ = '\0';
214
215    strOffset += str->length + 1;
216  }
217
218  return true;
219}
220
221
222bool MCCacheWriter::prepareExportVarList() {
223  size_t varCount = mpOwner->getExportVarCount();
224  size_t listSize = sizeof(OBCC_ExportVarList) + sizeof(void *) * varCount;
225
226  OBCC_ExportVarList *list = (OBCC_ExportVarList *)malloc(listSize);
227
228  if (!list) {
229    LOGE("Unable to allocate for export variable list\n");
230    return false;
231  }
232
233  mpExportVarListSection = list;
234  mpHeaderSection->export_var_list_size = listSize;
235
236  list->count = static_cast<size_t>(varCount);
237
238  mpOwner->getExportVarList(varCount, list->cached_addr_list);
239  return true;
240}
241
242
243bool MCCacheWriter::prepareExportFuncList() {
244  size_t funcCount = mpOwner->getExportFuncCount();
245  size_t listSize = sizeof(OBCC_ExportFuncList) + sizeof(void *) * funcCount;
246
247  OBCC_ExportFuncList *list = (OBCC_ExportFuncList *)malloc(listSize);
248
249  if (!list) {
250    LOGE("Unable to allocate for export function list\n");
251    return false;
252  }
253
254  mpExportFuncListSection = list;
255  mpHeaderSection->export_func_list_size = listSize;
256
257  list->count = static_cast<size_t>(funcCount);
258
259  mpOwner->getExportFuncList(funcCount, list->cached_addr_list);
260  return true;
261}
262
263
264bool MCCacheWriter::prepareObjectSlotList() {
265  size_t objectSlotCount = mpOwner->getObjectSlotCount();
266
267  size_t listSize = sizeof(OBCC_ObjectSlotList) +
268                    sizeof(uint32_t) * objectSlotCount;
269
270  OBCC_ObjectSlotList *list = (OBCC_ObjectSlotList *)malloc(listSize);
271
272  if (!list) {
273    LOGE("Unable to allocate for object slot list\n");
274    return false;
275  }
276
277  mpObjectSlotSection = list;
278  mpHeaderSection->object_slot_list_size = listSize;
279
280  list->count = objectSlotCount;
281
282  mpOwner->getObjectSlotList(objectSlotCount, list->object_slot_list);
283  return true;
284}
285
286
287bool MCCacheWriter::calcSectionOffset() {
288  size_t offset = sizeof(MCO_Header);
289
290#define OFFSET_INCREASE(NAME)                                               \
291  do {                                                                      \
292    /* Align to a word */                                                   \
293    size_t rem = offset % sizeof(int);                                      \
294    if (rem > 0) {                                                          \
295      offset += sizeof(int) - rem;                                          \
296    }                                                                       \
297                                                                            \
298    /* Save the offset and increase it */                                   \
299    mpHeaderSection->NAME##_offset = offset;                                \
300    offset += mpHeaderSection->NAME##_size;                                 \
301  } while (0)
302
303  OFFSET_INCREASE(str_pool);
304  OFFSET_INCREASE(depend_tab);
305  OFFSET_INCREASE(export_var_list);
306  OFFSET_INCREASE(export_func_list);
307  OFFSET_INCREASE(pragma_list);
308  OFFSET_INCREASE(func_table);
309  OFFSET_INCREASE(object_slot_list);
310
311#undef OFFSET_INCREASE
312
313  return true;
314}
315
316
317bool MCCacheWriter::writeAll() {
318#define WRITE_SECTION(NAME, OFFSET, SIZE, SECTION)                          \
319  do {                                                                      \
320    if (mInfoFile->seek(OFFSET, SEEK_SET) == -1) {                          \
321      LOGE("Unable to seek to " #NAME " section for writing.\n");           \
322      return false;                                                         \
323    }                                                                       \
324                                                                            \
325    if (mInfoFile->write(reinterpret_cast<char *>(SECTION), (SIZE)) !=      \
326        static_cast<ssize_t>(SIZE)) {                                       \
327      LOGE("Unable to write " #NAME " section to cache file.\n");           \
328      return false;                                                         \
329    }                                                                       \
330  } while (0)
331
332#define WRITE_SECTION_SIMPLE(NAME, SECTION)                                 \
333  WRITE_SECTION(NAME,                                                       \
334                mpHeaderSection->NAME##_offset,                             \
335                mpHeaderSection->NAME##_size,                               \
336                SECTION)
337
338  WRITE_SECTION(header, 0, sizeof(MCO_Header), mpHeaderSection);
339
340  WRITE_SECTION_SIMPLE(str_pool, mpStringPoolSection);
341  WRITE_SECTION_SIMPLE(depend_tab, mpDependencyTableSection);
342  WRITE_SECTION_SIMPLE(export_var_list, mpExportVarListSection);
343  WRITE_SECTION_SIMPLE(export_func_list, mpExportFuncListSection);
344  WRITE_SECTION_SIMPLE(pragma_list, mpPragmaListSection);
345  WRITE_SECTION_SIMPLE(object_slot_list, mpObjectSlotSection);
346
347#undef WRITE_SECTION_SIMPLE
348#undef WRITE_SECTION
349
350  if (static_cast<size_t>(mObjFile->write(mpOwner->getELF(),
351                                          mpOwner->getELFSize()))
352      != mpOwner->getELFSize()) {
353      LOGE("Unable to write ELF to cache file.\n");
354      return false;
355  }
356
357  return true;
358}
359
360} // namespace bcc
361#endif
362