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