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