1 /*
2  * Copyright (C) 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 "oat.h"
18 #include "utils.h"
19 
20 #include <string.h>
21 #include <zlib.h>
22 
23 namespace art {
24 
25 const uint8_t OatHeader::kOatMagic[] = { 'o', 'a', 't', '\n' };
26 const uint8_t OatHeader::kOatVersion[] = { '0', '4', '5', '\0' };
27 
ComputeOatHeaderSize(const SafeMap<std::string,std::string> * variable_data)28 static size_t ComputeOatHeaderSize(const SafeMap<std::string, std::string>* variable_data) {
29   size_t estimate = 0U;
30   if (variable_data != nullptr) {
31     SafeMap<std::string, std::string>::const_iterator it = variable_data->begin();
32     SafeMap<std::string, std::string>::const_iterator end = variable_data->end();
33     for ( ; it != end; ++it) {
34       estimate += it->first.length() + 1;
35       estimate += it->second.length() + 1;
36     }
37   }
38   return sizeof(OatHeader) + estimate;
39 }
40 
Create(InstructionSet instruction_set,const InstructionSetFeatures & instruction_set_features,const std::vector<const DexFile * > * dex_files,uint32_t image_file_location_oat_checksum,uint32_t image_file_location_oat_data_begin,const SafeMap<std::string,std::string> * variable_data)41 OatHeader* OatHeader::Create(InstructionSet instruction_set,
42                              const InstructionSetFeatures& instruction_set_features,
43                              const std::vector<const DexFile*>* dex_files,
44                              uint32_t image_file_location_oat_checksum,
45                              uint32_t image_file_location_oat_data_begin,
46                              const SafeMap<std::string, std::string>* variable_data) {
47   // Estimate size of optional data.
48   size_t needed_size = ComputeOatHeaderSize(variable_data);
49 
50   // Reserve enough memory.
51   void* memory = operator new (needed_size);
52 
53   // Create the OatHeader in-place.
54   return new (memory) OatHeader(instruction_set,
55                                 instruction_set_features,
56                                 dex_files,
57                                 image_file_location_oat_checksum,
58                                 image_file_location_oat_data_begin,
59                                 variable_data);
60 }
61 
OatHeader(InstructionSet instruction_set,const InstructionSetFeatures & instruction_set_features,const std::vector<const DexFile * > * dex_files,uint32_t image_file_location_oat_checksum,uint32_t image_file_location_oat_data_begin,const SafeMap<std::string,std::string> * variable_data)62 OatHeader::OatHeader(InstructionSet instruction_set,
63                      const InstructionSetFeatures& instruction_set_features,
64                      const std::vector<const DexFile*>* dex_files,
65                      uint32_t image_file_location_oat_checksum,
66                      uint32_t image_file_location_oat_data_begin,
67                      const SafeMap<std::string, std::string>* variable_data) {
68   memcpy(magic_, kOatMagic, sizeof(kOatMagic));
69   memcpy(version_, kOatVersion, sizeof(kOatVersion));
70   executable_offset_ = 0;
71   image_patch_delta_ = 0;
72 
73   adler32_checksum_ = adler32(0L, Z_NULL, 0);
74 
75   CHECK_NE(instruction_set, kNone);
76   instruction_set_ = instruction_set;
77   UpdateChecksum(&instruction_set_, sizeof(instruction_set_));
78 
79   instruction_set_features_ = instruction_set_features;
80   UpdateChecksum(&instruction_set_features_, sizeof(instruction_set_features_));
81 
82   dex_file_count_ = dex_files->size();
83   UpdateChecksum(&dex_file_count_, sizeof(dex_file_count_));
84 
85   image_file_location_oat_checksum_ = image_file_location_oat_checksum;
86   UpdateChecksum(&image_file_location_oat_checksum_, sizeof(image_file_location_oat_checksum_));
87 
88   CHECK(IsAligned<kPageSize>(image_file_location_oat_data_begin));
89   image_file_location_oat_data_begin_ = image_file_location_oat_data_begin;
90   UpdateChecksum(&image_file_location_oat_data_begin_, sizeof(image_file_location_oat_data_begin_));
91 
92   // Flatten the map. Will also update variable_size_data_size_.
93   Flatten(variable_data);
94 
95   // Update checksum for variable data size.
96   UpdateChecksum(&key_value_store_size_, sizeof(key_value_store_size_));
97 
98   // Update for data, if existing.
99   if (key_value_store_size_ > 0U) {
100     UpdateChecksum(&key_value_store_, key_value_store_size_);
101   }
102 
103   interpreter_to_interpreter_bridge_offset_ = 0;
104   interpreter_to_compiled_code_bridge_offset_ = 0;
105   jni_dlsym_lookup_offset_ = 0;
106   portable_imt_conflict_trampoline_offset_ = 0;
107   portable_resolution_trampoline_offset_ = 0;
108   portable_to_interpreter_bridge_offset_ = 0;
109   quick_generic_jni_trampoline_offset_ = 0;
110   quick_imt_conflict_trampoline_offset_ = 0;
111   quick_resolution_trampoline_offset_ = 0;
112   quick_to_interpreter_bridge_offset_ = 0;
113 }
114 
IsValid() const115 bool OatHeader::IsValid() const {
116   if (memcmp(magic_, kOatMagic, sizeof(kOatMagic)) != 0) {
117     return false;
118   }
119   if (memcmp(version_, kOatVersion, sizeof(kOatVersion)) != 0) {
120     return false;
121   }
122   if (!IsAligned<kPageSize>(executable_offset_)) {
123     return false;
124   }
125   if (!IsAligned<kPageSize>(image_patch_delta_)) {
126     return false;
127   }
128   return true;
129 }
130 
GetMagic() const131 const char* OatHeader::GetMagic() const {
132   CHECK(IsValid());
133   return reinterpret_cast<const char*>(magic_);
134 }
135 
GetChecksum() const136 uint32_t OatHeader::GetChecksum() const {
137   CHECK(IsValid());
138   return adler32_checksum_;
139 }
140 
UpdateChecksum(const void * data,size_t length)141 void OatHeader::UpdateChecksum(const void* data, size_t length) {
142   DCHECK(IsValid());
143   const uint8_t* bytes = reinterpret_cast<const uint8_t*>(data);
144   adler32_checksum_ = adler32(adler32_checksum_, bytes, length);
145 }
146 
GetInstructionSet() const147 InstructionSet OatHeader::GetInstructionSet() const {
148   CHECK(IsValid());
149   return instruction_set_;
150 }
151 
GetInstructionSetFeatures() const152 const InstructionSetFeatures& OatHeader::GetInstructionSetFeatures() const {
153   CHECK(IsValid());
154   return instruction_set_features_;
155 }
156 
GetExecutableOffset() const157 uint32_t OatHeader::GetExecutableOffset() const {
158   DCHECK(IsValid());
159   DCHECK_ALIGNED(executable_offset_, kPageSize);
160   CHECK_GT(executable_offset_, sizeof(OatHeader));
161   return executable_offset_;
162 }
163 
SetExecutableOffset(uint32_t executable_offset)164 void OatHeader::SetExecutableOffset(uint32_t executable_offset) {
165   DCHECK_ALIGNED(executable_offset, kPageSize);
166   CHECK_GT(executable_offset, sizeof(OatHeader));
167   DCHECK(IsValid());
168   DCHECK_EQ(executable_offset_, 0U);
169 
170   executable_offset_ = executable_offset;
171   UpdateChecksum(&executable_offset_, sizeof(executable_offset));
172 }
173 
GetInterpreterToInterpreterBridge() const174 const void* OatHeader::GetInterpreterToInterpreterBridge() const {
175   return reinterpret_cast<const uint8_t*>(this) + GetInterpreterToInterpreterBridgeOffset();
176 }
177 
GetInterpreterToInterpreterBridgeOffset() const178 uint32_t OatHeader::GetInterpreterToInterpreterBridgeOffset() const {
179   DCHECK(IsValid());
180   CHECK(interpreter_to_interpreter_bridge_offset_ == 0 ||
181         interpreter_to_interpreter_bridge_offset_ >= executable_offset_);
182   return interpreter_to_interpreter_bridge_offset_;
183 }
184 
SetInterpreterToInterpreterBridgeOffset(uint32_t offset)185 void OatHeader::SetInterpreterToInterpreterBridgeOffset(uint32_t offset) {
186   CHECK(offset == 0 || offset >= executable_offset_);
187   DCHECK(IsValid());
188   DCHECK_EQ(interpreter_to_interpreter_bridge_offset_, 0U) << offset;
189 
190   interpreter_to_interpreter_bridge_offset_ = offset;
191   UpdateChecksum(&interpreter_to_interpreter_bridge_offset_, sizeof(offset));
192 }
193 
GetInterpreterToCompiledCodeBridge() const194 const void* OatHeader::GetInterpreterToCompiledCodeBridge() const {
195   return reinterpret_cast<const uint8_t*>(this) + GetInterpreterToCompiledCodeBridgeOffset();
196 }
197 
GetInterpreterToCompiledCodeBridgeOffset() const198 uint32_t OatHeader::GetInterpreterToCompiledCodeBridgeOffset() const {
199   DCHECK(IsValid());
200   CHECK_GE(interpreter_to_compiled_code_bridge_offset_, interpreter_to_interpreter_bridge_offset_);
201   return interpreter_to_compiled_code_bridge_offset_;
202 }
203 
SetInterpreterToCompiledCodeBridgeOffset(uint32_t offset)204 void OatHeader::SetInterpreterToCompiledCodeBridgeOffset(uint32_t offset) {
205   CHECK(offset == 0 || offset >= interpreter_to_interpreter_bridge_offset_);
206   DCHECK(IsValid());
207   DCHECK_EQ(interpreter_to_compiled_code_bridge_offset_, 0U) << offset;
208 
209   interpreter_to_compiled_code_bridge_offset_ = offset;
210   UpdateChecksum(&interpreter_to_compiled_code_bridge_offset_, sizeof(offset));
211 }
212 
GetJniDlsymLookup() const213 const void* OatHeader::GetJniDlsymLookup() const {
214   return reinterpret_cast<const uint8_t*>(this) + GetJniDlsymLookupOffset();
215 }
216 
GetJniDlsymLookupOffset() const217 uint32_t OatHeader::GetJniDlsymLookupOffset() const {
218   DCHECK(IsValid());
219   CHECK_GE(jni_dlsym_lookup_offset_, interpreter_to_compiled_code_bridge_offset_);
220   return jni_dlsym_lookup_offset_;
221 }
222 
SetJniDlsymLookupOffset(uint32_t offset)223 void OatHeader::SetJniDlsymLookupOffset(uint32_t offset) {
224   CHECK(offset == 0 || offset >= interpreter_to_compiled_code_bridge_offset_);
225   DCHECK(IsValid());
226   DCHECK_EQ(jni_dlsym_lookup_offset_, 0U) << offset;
227 
228   jni_dlsym_lookup_offset_ = offset;
229   UpdateChecksum(&jni_dlsym_lookup_offset_, sizeof(offset));
230 }
231 
GetPortableImtConflictTrampoline() const232 const void* OatHeader::GetPortableImtConflictTrampoline() const {
233   return reinterpret_cast<const uint8_t*>(this) + GetPortableImtConflictTrampolineOffset();
234 }
235 
GetPortableImtConflictTrampolineOffset() const236 uint32_t OatHeader::GetPortableImtConflictTrampolineOffset() const {
237   DCHECK(IsValid());
238   CHECK_GE(portable_imt_conflict_trampoline_offset_, jni_dlsym_lookup_offset_);
239   return portable_imt_conflict_trampoline_offset_;
240 }
241 
SetPortableImtConflictTrampolineOffset(uint32_t offset)242 void OatHeader::SetPortableImtConflictTrampolineOffset(uint32_t offset) {
243   CHECK(offset == 0 || offset >= jni_dlsym_lookup_offset_);
244   DCHECK(IsValid());
245   DCHECK_EQ(portable_imt_conflict_trampoline_offset_, 0U) << offset;
246 
247   portable_imt_conflict_trampoline_offset_ = offset;
248   UpdateChecksum(&portable_imt_conflict_trampoline_offset_, sizeof(offset));
249 }
250 
GetPortableResolutionTrampoline() const251 const void* OatHeader::GetPortableResolutionTrampoline() const {
252   return reinterpret_cast<const uint8_t*>(this) + GetPortableResolutionTrampolineOffset();
253 }
254 
GetPortableResolutionTrampolineOffset() const255 uint32_t OatHeader::GetPortableResolutionTrampolineOffset() const {
256   DCHECK(IsValid());
257   CHECK_GE(portable_resolution_trampoline_offset_, portable_imt_conflict_trampoline_offset_);
258   return portable_resolution_trampoline_offset_;
259 }
260 
SetPortableResolutionTrampolineOffset(uint32_t offset)261 void OatHeader::SetPortableResolutionTrampolineOffset(uint32_t offset) {
262   CHECK(offset == 0 || offset >= portable_imt_conflict_trampoline_offset_);
263   DCHECK(IsValid());
264   DCHECK_EQ(portable_resolution_trampoline_offset_, 0U) << offset;
265 
266   portable_resolution_trampoline_offset_ = offset;
267   UpdateChecksum(&portable_resolution_trampoline_offset_, sizeof(offset));
268 }
269 
GetPortableToInterpreterBridge() const270 const void* OatHeader::GetPortableToInterpreterBridge() const {
271   return reinterpret_cast<const uint8_t*>(this) + GetPortableToInterpreterBridgeOffset();
272 }
273 
GetPortableToInterpreterBridgeOffset() const274 uint32_t OatHeader::GetPortableToInterpreterBridgeOffset() const {
275   DCHECK(IsValid());
276   CHECK_GE(portable_to_interpreter_bridge_offset_, portable_resolution_trampoline_offset_);
277   return portable_to_interpreter_bridge_offset_;
278 }
279 
SetPortableToInterpreterBridgeOffset(uint32_t offset)280 void OatHeader::SetPortableToInterpreterBridgeOffset(uint32_t offset) {
281   CHECK(offset == 0 || offset >= portable_resolution_trampoline_offset_);
282   DCHECK(IsValid());
283   DCHECK_EQ(portable_to_interpreter_bridge_offset_, 0U) << offset;
284 
285   portable_to_interpreter_bridge_offset_ = offset;
286   UpdateChecksum(&portable_to_interpreter_bridge_offset_, sizeof(offset));
287 }
288 
GetQuickGenericJniTrampoline() const289 const void* OatHeader::GetQuickGenericJniTrampoline() const {
290   return reinterpret_cast<const uint8_t*>(this) + GetQuickGenericJniTrampolineOffset();
291 }
292 
GetQuickGenericJniTrampolineOffset() const293 uint32_t OatHeader::GetQuickGenericJniTrampolineOffset() const {
294   DCHECK(IsValid());
295   CHECK_GE(quick_generic_jni_trampoline_offset_, portable_to_interpreter_bridge_offset_);
296   return quick_generic_jni_trampoline_offset_;
297 }
298 
SetQuickGenericJniTrampolineOffset(uint32_t offset)299 void OatHeader::SetQuickGenericJniTrampolineOffset(uint32_t offset) {
300   CHECK(offset == 0 || offset >= portable_to_interpreter_bridge_offset_);
301   DCHECK(IsValid());
302   DCHECK_EQ(quick_generic_jni_trampoline_offset_, 0U) << offset;
303 
304   quick_generic_jni_trampoline_offset_ = offset;
305   UpdateChecksum(&quick_generic_jni_trampoline_offset_, sizeof(offset));
306 }
307 
GetQuickImtConflictTrampoline() const308 const void* OatHeader::GetQuickImtConflictTrampoline() const {
309   return reinterpret_cast<const uint8_t*>(this) + GetQuickImtConflictTrampolineOffset();
310 }
311 
GetQuickImtConflictTrampolineOffset() const312 uint32_t OatHeader::GetQuickImtConflictTrampolineOffset() const {
313   DCHECK(IsValid());
314   CHECK_GE(quick_imt_conflict_trampoline_offset_, quick_generic_jni_trampoline_offset_);
315   return quick_imt_conflict_trampoline_offset_;
316 }
317 
SetQuickImtConflictTrampolineOffset(uint32_t offset)318 void OatHeader::SetQuickImtConflictTrampolineOffset(uint32_t offset) {
319   CHECK(offset == 0 || offset >= quick_generic_jni_trampoline_offset_);
320   DCHECK(IsValid());
321   DCHECK_EQ(quick_imt_conflict_trampoline_offset_, 0U) << offset;
322 
323   quick_imt_conflict_trampoline_offset_ = offset;
324   UpdateChecksum(&quick_imt_conflict_trampoline_offset_, sizeof(offset));
325 }
326 
GetQuickResolutionTrampoline() const327 const void* OatHeader::GetQuickResolutionTrampoline() const {
328   return reinterpret_cast<const uint8_t*>(this) + GetQuickResolutionTrampolineOffset();
329 }
330 
GetQuickResolutionTrampolineOffset() const331 uint32_t OatHeader::GetQuickResolutionTrampolineOffset() const {
332   DCHECK(IsValid());
333   CHECK_GE(quick_resolution_trampoline_offset_, quick_imt_conflict_trampoline_offset_);
334   return quick_resolution_trampoline_offset_;
335 }
336 
SetQuickResolutionTrampolineOffset(uint32_t offset)337 void OatHeader::SetQuickResolutionTrampolineOffset(uint32_t offset) {
338   CHECK(offset == 0 || offset >= quick_imt_conflict_trampoline_offset_);
339   DCHECK(IsValid());
340   DCHECK_EQ(quick_resolution_trampoline_offset_, 0U) << offset;
341 
342   quick_resolution_trampoline_offset_ = offset;
343   UpdateChecksum(&quick_resolution_trampoline_offset_, sizeof(offset));
344 }
345 
GetQuickToInterpreterBridge() const346 const void* OatHeader::GetQuickToInterpreterBridge() const {
347   return reinterpret_cast<const uint8_t*>(this) + GetQuickToInterpreterBridgeOffset();
348 }
349 
GetQuickToInterpreterBridgeOffset() const350 uint32_t OatHeader::GetQuickToInterpreterBridgeOffset() const {
351   DCHECK(IsValid());
352   CHECK_GE(quick_to_interpreter_bridge_offset_, quick_resolution_trampoline_offset_);
353   return quick_to_interpreter_bridge_offset_;
354 }
355 
SetQuickToInterpreterBridgeOffset(uint32_t offset)356 void OatHeader::SetQuickToInterpreterBridgeOffset(uint32_t offset) {
357   CHECK(offset == 0 || offset >= quick_resolution_trampoline_offset_);
358   DCHECK(IsValid());
359   DCHECK_EQ(quick_to_interpreter_bridge_offset_, 0U) << offset;
360 
361   quick_to_interpreter_bridge_offset_ = offset;
362   UpdateChecksum(&quick_to_interpreter_bridge_offset_, sizeof(offset));
363 }
364 
GetImagePatchDelta() const365 int32_t OatHeader::GetImagePatchDelta() const {
366   CHECK(IsValid());
367   return image_patch_delta_;
368 }
369 
RelocateOat(off_t delta)370 void OatHeader::RelocateOat(off_t delta) {
371   CHECK(IsValid());
372   CHECK_ALIGNED(delta, kPageSize);
373   image_patch_delta_ += delta;
374   if (image_file_location_oat_data_begin_ != 0) {
375     image_file_location_oat_data_begin_ += delta;
376   }
377 }
378 
SetImagePatchDelta(int32_t off)379 void OatHeader::SetImagePatchDelta(int32_t off) {
380   CHECK(IsValid());
381   CHECK_ALIGNED(off, kPageSize);
382   image_patch_delta_ = off;
383 }
384 
GetImageFileLocationOatChecksum() const385 uint32_t OatHeader::GetImageFileLocationOatChecksum() const {
386   CHECK(IsValid());
387   return image_file_location_oat_checksum_;
388 }
389 
GetImageFileLocationOatDataBegin() const390 uint32_t OatHeader::GetImageFileLocationOatDataBegin() const {
391   CHECK(IsValid());
392   return image_file_location_oat_data_begin_;
393 }
394 
GetKeyValueStoreSize() const395 uint32_t OatHeader::GetKeyValueStoreSize() const {
396   CHECK(IsValid());
397   return key_value_store_size_;
398 }
399 
GetKeyValueStore() const400 const uint8_t* OatHeader::GetKeyValueStore() const {
401   CHECK(IsValid());
402   return key_value_store_;
403 }
404 
405 // Advance start until it is either end or \0.
ParseString(const char * start,const char * end)406 static const char* ParseString(const char* start, const char* end) {
407   while (start < end && *start != 0) {
408     start++;
409   }
410   return start;
411 }
412 
GetStoreValueByKey(const char * key) const413 const char* OatHeader::GetStoreValueByKey(const char* key) const {
414   const char* ptr = reinterpret_cast<const char*>(&key_value_store_);
415   const char* end = ptr + key_value_store_size_;
416 
417   while (ptr < end) {
418     // Scan for a closing zero.
419     const char* str_end = ParseString(ptr, end);
420     if (str_end < end) {
421       if (strcmp(key, ptr) == 0) {
422         // Same as key. Check if value is OK.
423         if (ParseString(str_end + 1, end) < end) {
424           return str_end + 1;
425         }
426       } else {
427         // Different from key. Advance over the value.
428         ptr = ParseString(str_end + 1, end) + 1;
429       }
430     } else {
431       break;
432     }
433   }
434   // Not found.
435   return nullptr;
436 }
437 
GetStoreKeyValuePairByIndex(size_t index,const char ** key,const char ** value) const438 bool OatHeader::GetStoreKeyValuePairByIndex(size_t index, const char** key,
439                                             const char** value) const {
440   const char* ptr = reinterpret_cast<const char*>(&key_value_store_);
441   const char* end = ptr + key_value_store_size_;
442   ssize_t counter = static_cast<ssize_t>(index);
443 
444   while (ptr < end && counter >= 0) {
445     // Scan for a closing zero.
446     const char* str_end = ParseString(ptr, end);
447     if (str_end < end) {
448       const char* maybe_key = ptr;
449       ptr = ParseString(str_end + 1, end) + 1;
450       if (ptr <= end) {
451         if (counter == 0) {
452           *key = maybe_key;
453           *value = str_end + 1;
454           return true;
455         } else {
456           counter--;
457         }
458       } else {
459         return false;
460       }
461     } else {
462       break;
463     }
464   }
465   // Not found.
466   return false;
467 }
468 
GetHeaderSize() const469 size_t OatHeader::GetHeaderSize() const {
470   return sizeof(OatHeader) + key_value_store_size_;
471 }
472 
IsPic() const473 bool OatHeader::IsPic() const {
474   const char* pic_string = GetStoreValueByKey(OatHeader::kPicKey);
475   static const char kTrue[] = "true";
476   return (pic_string != nullptr && strncmp(pic_string, kTrue, sizeof(kTrue)) == 0);
477 }
478 
Flatten(const SafeMap<std::string,std::string> * key_value_store)479 void OatHeader::Flatten(const SafeMap<std::string, std::string>* key_value_store) {
480   char* data_ptr = reinterpret_cast<char*>(&key_value_store_);
481   if (key_value_store != nullptr) {
482     SafeMap<std::string, std::string>::const_iterator it = key_value_store->begin();
483     SafeMap<std::string, std::string>::const_iterator end = key_value_store->end();
484     for ( ; it != end; ++it) {
485       strcpy(data_ptr, it->first.c_str());
486       data_ptr += it->first.length() + 1;
487       strcpy(data_ptr, it->second.c_str());
488       data_ptr += it->second.length() + 1;
489     }
490   }
491   key_value_store_size_ = data_ptr - reinterpret_cast<char*>(&key_value_store_);
492 }
493 
OatMethodOffsets(uint32_t code_offset)494 OatMethodOffsets::OatMethodOffsets(uint32_t code_offset) : code_offset_(code_offset) {
495 }
496 
~OatMethodOffsets()497 OatMethodOffsets::~OatMethodOffsets() {}
498 
OatQuickMethodHeader(uint32_t mapping_table_offset,uint32_t vmap_table_offset,uint32_t gc_map_offset,uint32_t frame_size_in_bytes,uint32_t core_spill_mask,uint32_t fp_spill_mask,uint32_t code_size)499 OatQuickMethodHeader::OatQuickMethodHeader(
500     uint32_t mapping_table_offset, uint32_t vmap_table_offset, uint32_t gc_map_offset,
501     uint32_t frame_size_in_bytes, uint32_t core_spill_mask, uint32_t fp_spill_mask,
502     uint32_t code_size)
503     : mapping_table_offset_(mapping_table_offset), vmap_table_offset_(vmap_table_offset),
504       gc_map_offset_(gc_map_offset),
505       frame_info_(frame_size_in_bytes, core_spill_mask, fp_spill_mask), code_size_(code_size) {
506 }
507 
~OatQuickMethodHeader()508 OatQuickMethodHeader::~OatQuickMethodHeader() {}
509 
510 }  // namespace art
511