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 #ifndef ART_RUNTIME_ART_METHOD_INL_H_
18 #define ART_RUNTIME_ART_METHOD_INL_H_
19 
20 #include "art_method.h"
21 
22 #include "art_field.h"
23 #include "base/logging.h"
24 #include "dex_file.h"
25 #include "dex_file-inl.h"
26 #include "gc_root-inl.h"
27 #include "mirror/class-inl.h"
28 #include "mirror/dex_cache.h"
29 #include "mirror/object-inl.h"
30 #include "mirror/object_array.h"
31 #include "oat.h"
32 #include "quick/quick_method_frame_info.h"
33 #include "read_barrier-inl.h"
34 #include "runtime-inl.h"
35 #include "utils.h"
36 
37 namespace art {
38 
GetDeclaringClassUnchecked()39 inline mirror::Class* ArtMethod::GetDeclaringClassUnchecked() {
40   return declaring_class_.Read();
41 }
42 
GetDeclaringClassNoBarrier()43 inline mirror::Class* ArtMethod::GetDeclaringClassNoBarrier() {
44   return declaring_class_.Read<kWithoutReadBarrier>();
45 }
46 
GetDeclaringClass()47 inline mirror::Class* ArtMethod::GetDeclaringClass() {
48   mirror::Class* result = GetDeclaringClassUnchecked();
49   if (kIsDebugBuild) {
50     if (!IsRuntimeMethod()) {
51       CHECK(result != nullptr) << this;
52       CHECK(result->IsIdxLoaded() || result->IsErroneous())
53           << result->GetStatus() << " " << PrettyClass(result);
54     } else {
55       CHECK(result == nullptr) << this;
56     }
57   }
58   return result;
59 }
60 
SetDeclaringClass(mirror::Class * new_declaring_class)61 inline void ArtMethod::SetDeclaringClass(mirror::Class* new_declaring_class) {
62   declaring_class_ = GcRoot<mirror::Class>(new_declaring_class);
63 }
64 
GetAccessFlags()65 inline uint32_t ArtMethod::GetAccessFlags() {
66   DCHECK(IsRuntimeMethod() || GetDeclaringClass()->IsIdxLoaded() ||
67          GetDeclaringClass()->IsErroneous());
68   return access_flags_;
69 }
70 
GetMethodIndex()71 inline uint16_t ArtMethod::GetMethodIndex() {
72   DCHECK(IsRuntimeMethod() || GetDeclaringClass()->IsResolved() ||
73          GetDeclaringClass()->IsErroneous());
74   return method_index_;
75 }
76 
GetMethodIndexDuringLinking()77 inline uint16_t ArtMethod::GetMethodIndexDuringLinking() {
78   return method_index_;
79 }
80 
GetDexMethodIndex()81 inline uint32_t ArtMethod::GetDexMethodIndex() {
82   DCHECK(IsRuntimeMethod() || GetDeclaringClass()->IsIdxLoaded() ||
83          GetDeclaringClass()->IsErroneous());
84   return dex_method_index_;
85 }
86 
GetDexCacheResolvedMethods()87 inline mirror::PointerArray* ArtMethod::GetDexCacheResolvedMethods() {
88   return dex_cache_resolved_methods_.Read();
89 }
90 
GetDexCacheResolvedMethod(uint16_t method_index,size_t ptr_size)91 inline ArtMethod* ArtMethod::GetDexCacheResolvedMethod(uint16_t method_index, size_t ptr_size) {
92   auto* method = GetDexCacheResolvedMethods()->GetElementPtrSize<ArtMethod*>(
93       method_index, ptr_size);
94   if (LIKELY(method != nullptr)) {
95     auto* declaring_class = method->GetDeclaringClass();
96     if (LIKELY(declaring_class == nullptr || !declaring_class->IsErroneous())) {
97       return method;
98     }
99   }
100   return nullptr;
101 }
102 
SetDexCacheResolvedMethod(uint16_t method_idx,ArtMethod * new_method,size_t ptr_size)103 inline void ArtMethod::SetDexCacheResolvedMethod(uint16_t method_idx, ArtMethod* new_method,
104                                                  size_t ptr_size) {
105   DCHECK(new_method == nullptr || new_method->GetDeclaringClass() != nullptr);
106   GetDexCacheResolvedMethods()->SetElementPtrSize(method_idx, new_method, ptr_size);
107 }
108 
HasDexCacheResolvedMethods()109 inline bool ArtMethod::HasDexCacheResolvedMethods() {
110   return GetDexCacheResolvedMethods() != nullptr;
111 }
112 
HasSameDexCacheResolvedMethods(mirror::PointerArray * other_cache)113 inline bool ArtMethod::HasSameDexCacheResolvedMethods(mirror::PointerArray* other_cache) {
114   return GetDexCacheResolvedMethods() == other_cache;
115 }
116 
HasSameDexCacheResolvedMethods(ArtMethod * other)117 inline bool ArtMethod::HasSameDexCacheResolvedMethods(ArtMethod* other) {
118   return GetDexCacheResolvedMethods() == other->GetDexCacheResolvedMethods();
119 }
120 
GetDexCacheResolvedTypes()121 inline mirror::ObjectArray<mirror::Class>* ArtMethod::GetDexCacheResolvedTypes() {
122   return dex_cache_resolved_types_.Read();
123 }
124 
125 template <bool kWithCheck>
GetDexCacheResolvedType(uint32_t type_index)126 inline mirror::Class* ArtMethod::GetDexCacheResolvedType(uint32_t type_index) {
127   mirror::Class* klass = kWithCheck ?
128       GetDexCacheResolvedTypes()->Get(type_index) :
129       GetDexCacheResolvedTypes()->GetWithoutChecks(type_index);
130   return (klass != nullptr && !klass->IsErroneous()) ? klass : nullptr;
131 }
132 
HasDexCacheResolvedTypes()133 inline bool ArtMethod::HasDexCacheResolvedTypes() {
134   return GetDexCacheResolvedTypes() != nullptr;
135 }
136 
HasSameDexCacheResolvedTypes(mirror::ObjectArray<mirror::Class> * other_cache)137 inline bool ArtMethod::HasSameDexCacheResolvedTypes(
138     mirror::ObjectArray<mirror::Class>* other_cache) {
139   return GetDexCacheResolvedTypes() == other_cache;
140 }
141 
HasSameDexCacheResolvedTypes(ArtMethod * other)142 inline bool ArtMethod::HasSameDexCacheResolvedTypes(ArtMethod* other) {
143   return GetDexCacheResolvedTypes() == other->GetDexCacheResolvedTypes();
144 }
145 
GetClassFromTypeIndex(uint16_t type_idx,bool resolve)146 inline mirror::Class* ArtMethod::GetClassFromTypeIndex(uint16_t type_idx, bool resolve) {
147   mirror::Class* type = GetDexCacheResolvedType(type_idx);
148   if (type == nullptr && resolve) {
149     type = Runtime::Current()->GetClassLinker()->ResolveType(type_idx, this);
150     CHECK(type != nullptr || Thread::Current()->IsExceptionPending());
151   }
152   return type;
153 }
154 
GetCodeSize()155 inline uint32_t ArtMethod::GetCodeSize() {
156   DCHECK(!IsRuntimeMethod() && !IsProxyMethod()) << PrettyMethod(this);
157   return GetCodeSize(EntryPointToCodePointer(GetEntryPointFromQuickCompiledCode()));
158 }
159 
GetCodeSize(const void * code)160 inline uint32_t ArtMethod::GetCodeSize(const void* code) {
161   if (code == nullptr) {
162     return 0u;
163   }
164   return reinterpret_cast<const OatQuickMethodHeader*>(code)[-1].code_size_;
165 }
166 
CheckIncompatibleClassChange(InvokeType type)167 inline bool ArtMethod::CheckIncompatibleClassChange(InvokeType type) {
168   switch (type) {
169     case kStatic:
170       return !IsStatic();
171     case kDirect:
172       return !IsDirect() || IsStatic();
173     case kVirtual: {
174       mirror::Class* methods_class = GetDeclaringClass();
175       return IsDirect() || (methods_class->IsInterface() && !IsMiranda());
176     }
177     case kSuper:
178       // Constructors and static methods are called with invoke-direct.
179       // Interface methods cannot be invoked with invoke-super.
180       return IsConstructor() || IsStatic() || GetDeclaringClass()->IsInterface();
181     case kInterface: {
182       mirror::Class* methods_class = GetDeclaringClass();
183       return IsDirect() || !(methods_class->IsInterface() || methods_class->IsObjectClass());
184     }
185     default:
186       LOG(FATAL) << "Unreachable - invocation type: " << type;
187       UNREACHABLE();
188   }
189 }
190 
GetQuickOatCodeOffset()191 inline uint32_t ArtMethod::GetQuickOatCodeOffset() {
192   DCHECK(!Runtime::Current()->IsStarted());
193   return PointerToLowMemUInt32(GetEntryPointFromQuickCompiledCode());
194 }
195 
SetQuickOatCodeOffset(uint32_t code_offset)196 inline void ArtMethod::SetQuickOatCodeOffset(uint32_t code_offset) {
197   DCHECK(!Runtime::Current()->IsStarted());
198   SetEntryPointFromQuickCompiledCode(reinterpret_cast<void*>(code_offset));
199 }
200 
GetMappingTable(size_t pointer_size)201 inline const uint8_t* ArtMethod::GetMappingTable(size_t pointer_size) {
202   const void* code_pointer = GetQuickOatCodePointer(pointer_size);
203   if (code_pointer == nullptr) {
204     return nullptr;
205   }
206   return GetMappingTable(code_pointer, pointer_size);
207 }
208 
GetMappingTable(const void * code_pointer,size_t pointer_size)209 inline const uint8_t* ArtMethod::GetMappingTable(const void* code_pointer, size_t pointer_size) {
210   DCHECK(code_pointer != nullptr);
211   DCHECK_EQ(code_pointer, GetQuickOatCodePointer(pointer_size));
212   uint32_t offset =
213       reinterpret_cast<const OatQuickMethodHeader*>(code_pointer)[-1].mapping_table_offset_;
214   if (UNLIKELY(offset == 0u)) {
215     return nullptr;
216   }
217   return reinterpret_cast<const uint8_t*>(code_pointer) - offset;
218 }
219 
GetVmapTable(size_t pointer_size)220 inline const uint8_t* ArtMethod::GetVmapTable(size_t pointer_size) {
221   const void* code_pointer = GetQuickOatCodePointer(pointer_size);
222   if (code_pointer == nullptr) {
223     return nullptr;
224   }
225   return GetVmapTable(code_pointer, pointer_size);
226 }
227 
GetVmapTable(const void * code_pointer,size_t pointer_size)228 inline const uint8_t* ArtMethod::GetVmapTable(const void* code_pointer, size_t pointer_size) {
229   CHECK(!IsOptimized(pointer_size)) << "Unimplemented vmap table for optimized compiler";
230   DCHECK(code_pointer != nullptr);
231   DCHECK_EQ(code_pointer, GetQuickOatCodePointer(pointer_size));
232   uint32_t offset =
233       reinterpret_cast<const OatQuickMethodHeader*>(code_pointer)[-1].vmap_table_offset_;
234   if (UNLIKELY(offset == 0u)) {
235     return nullptr;
236   }
237   return reinterpret_cast<const uint8_t*>(code_pointer) - offset;
238 }
239 
GetOptimizedCodeInfo()240 inline CodeInfo ArtMethod::GetOptimizedCodeInfo() {
241   DCHECK(IsOptimized(sizeof(void*)));
242   const void* code_pointer = GetQuickOatCodePointer(sizeof(void*));
243   DCHECK(code_pointer != nullptr);
244   uint32_t offset =
245       reinterpret_cast<const OatQuickMethodHeader*>(code_pointer)[-1].vmap_table_offset_;
246   const void* data =
247       reinterpret_cast<const void*>(reinterpret_cast<const uint8_t*>(code_pointer) - offset);
248   return CodeInfo(data);
249 }
250 
GetNativeGcMap(size_t pointer_size)251 inline const uint8_t* ArtMethod::GetNativeGcMap(size_t pointer_size) {
252   const void* code_pointer = GetQuickOatCodePointer(pointer_size);
253   if (code_pointer == nullptr) {
254     return nullptr;
255   }
256   return GetNativeGcMap(code_pointer, pointer_size);
257 }
258 
GetNativeGcMap(const void * code_pointer,size_t pointer_size)259 inline const uint8_t* ArtMethod::GetNativeGcMap(const void* code_pointer, size_t pointer_size) {
260   DCHECK(code_pointer != nullptr);
261   DCHECK_EQ(code_pointer, GetQuickOatCodePointer(pointer_size));
262   uint32_t offset =
263       reinterpret_cast<const OatQuickMethodHeader*>(code_pointer)[-1].gc_map_offset_;
264   if (UNLIKELY(offset == 0u)) {
265     return nullptr;
266   }
267   return reinterpret_cast<const uint8_t*>(code_pointer) - offset;
268 }
269 
IsRuntimeMethod()270 inline bool ArtMethod::IsRuntimeMethod() {
271   return dex_method_index_ == DexFile::kDexNoIndex;
272 }
273 
IsCalleeSaveMethod()274 inline bool ArtMethod::IsCalleeSaveMethod() {
275   if (!IsRuntimeMethod()) {
276     return false;
277   }
278   Runtime* runtime = Runtime::Current();
279   bool result = false;
280   for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) {
281     if (this == runtime->GetCalleeSaveMethod(Runtime::CalleeSaveType(i))) {
282       result = true;
283       break;
284     }
285   }
286   return result;
287 }
288 
IsResolutionMethod()289 inline bool ArtMethod::IsResolutionMethod() {
290   bool result = this == Runtime::Current()->GetResolutionMethod();
291   // Check that if we do think it is phony it looks like the resolution method.
292   DCHECK(!result || IsRuntimeMethod());
293   return result;
294 }
295 
IsImtConflictMethod()296 inline bool ArtMethod::IsImtConflictMethod() {
297   bool result = this == Runtime::Current()->GetImtConflictMethod();
298   // Check that if we do think it is phony it looks like the imt conflict method.
299   DCHECK(!result || IsRuntimeMethod());
300   return result;
301 }
302 
IsImtUnimplementedMethod()303 inline bool ArtMethod::IsImtUnimplementedMethod() {
304   bool result = this == Runtime::Current()->GetImtUnimplementedMethod();
305   // Check that if we do think it is phony it looks like the imt unimplemented method.
306   DCHECK(!result || IsRuntimeMethod());
307   return result;
308 }
309 
NativeQuickPcOffset(const uintptr_t pc)310 inline uintptr_t ArtMethod::NativeQuickPcOffset(const uintptr_t pc) {
311   const void* code = Runtime::Current()->GetInstrumentation()->GetQuickCodeFor(
312       this, sizeof(void*));
313   return pc - reinterpret_cast<uintptr_t>(code);
314 }
315 
GetQuickFrameInfo(const void * code_pointer)316 inline QuickMethodFrameInfo ArtMethod::GetQuickFrameInfo(const void* code_pointer) {
317   DCHECK(code_pointer != nullptr);
318   if (kIsDebugBuild && !IsProxyMethod()) {
319     CHECK_EQ(code_pointer, GetQuickOatCodePointer(sizeof(void*)));
320   }
321   return reinterpret_cast<const OatQuickMethodHeader*>(code_pointer)[-1].frame_info_;
322 }
323 
GetDexFile()324 inline const DexFile* ArtMethod::GetDexFile() {
325   return GetDexCache()->GetDexFile();
326 }
327 
GetDeclaringClassDescriptor()328 inline const char* ArtMethod::GetDeclaringClassDescriptor() {
329   uint32_t dex_method_idx = GetDexMethodIndex();
330   if (UNLIKELY(dex_method_idx == DexFile::kDexNoIndex)) {
331     return "<runtime method>";
332   }
333   DCHECK(!IsProxyMethod());
334   const DexFile* dex_file = GetDexFile();
335   return dex_file->GetMethodDeclaringClassDescriptor(dex_file->GetMethodId(dex_method_idx));
336 }
337 
GetShorty(uint32_t * out_length)338 inline const char* ArtMethod::GetShorty(uint32_t* out_length) {
339   DCHECK(!IsProxyMethod());
340   const DexFile* dex_file = GetDexFile();
341   return dex_file->GetMethodShorty(dex_file->GetMethodId(GetDexMethodIndex()), out_length);
342 }
343 
GetSignature()344 inline const Signature ArtMethod::GetSignature() {
345   uint32_t dex_method_idx = GetDexMethodIndex();
346   if (dex_method_idx != DexFile::kDexNoIndex) {
347     DCHECK(!IsProxyMethod());
348     const DexFile* dex_file = GetDexFile();
349     return dex_file->GetMethodSignature(dex_file->GetMethodId(dex_method_idx));
350   }
351   return Signature::NoSignature();
352 }
353 
GetName()354 inline const char* ArtMethod::GetName() {
355   uint32_t dex_method_idx = GetDexMethodIndex();
356   if (LIKELY(dex_method_idx != DexFile::kDexNoIndex)) {
357     DCHECK(!IsProxyMethod());
358     const DexFile* dex_file = GetDexFile();
359     return dex_file->GetMethodName(dex_file->GetMethodId(dex_method_idx));
360   }
361   Runtime* const runtime = Runtime::Current();
362   if (this == runtime->GetResolutionMethod()) {
363     return "<runtime internal resolution method>";
364   } else if (this == runtime->GetImtConflictMethod()) {
365     return "<runtime internal imt conflict method>";
366   } else if (this == runtime->GetCalleeSaveMethod(Runtime::kSaveAll)) {
367     return "<runtime internal callee-save all registers method>";
368   } else if (this == runtime->GetCalleeSaveMethod(Runtime::kRefsOnly)) {
369     return "<runtime internal callee-save reference registers method>";
370   } else if (this == runtime->GetCalleeSaveMethod(Runtime::kRefsAndArgs)) {
371     return "<runtime internal callee-save reference and argument registers method>";
372   } else {
373     return "<unknown runtime internal method>";
374   }
375 }
376 
GetCodeItem()377 inline const DexFile::CodeItem* ArtMethod::GetCodeItem() {
378   return GetDeclaringClass()->GetDexFile().GetCodeItem(GetCodeItemOffset());
379 }
380 
IsResolvedTypeIdx(uint16_t type_idx)381 inline bool ArtMethod::IsResolvedTypeIdx(uint16_t type_idx) {
382   DCHECK(!IsProxyMethod());
383   return GetDexCacheResolvedType(type_idx) != nullptr;
384 }
385 
GetLineNumFromDexPC(uint32_t dex_pc)386 inline int32_t ArtMethod::GetLineNumFromDexPC(uint32_t dex_pc) {
387   DCHECK(!IsProxyMethod());
388   if (dex_pc == DexFile::kDexNoIndex) {
389     return IsNative() ? -2 : -1;
390   }
391   return GetDexFile()->GetLineNumFromPC(this, dex_pc);
392 }
393 
GetPrototype()394 inline const DexFile::ProtoId& ArtMethod::GetPrototype() {
395   DCHECK(!IsProxyMethod());
396   const DexFile* dex_file = GetDexFile();
397   return dex_file->GetMethodPrototype(dex_file->GetMethodId(GetDexMethodIndex()));
398 }
399 
GetParameterTypeList()400 inline const DexFile::TypeList* ArtMethod::GetParameterTypeList() {
401   DCHECK(!IsProxyMethod());
402   const DexFile* dex_file = GetDexFile();
403   const DexFile::ProtoId& proto = dex_file->GetMethodPrototype(
404       dex_file->GetMethodId(GetDexMethodIndex()));
405   return dex_file->GetProtoParameters(proto);
406 }
407 
GetDeclaringClassSourceFile()408 inline const char* ArtMethod::GetDeclaringClassSourceFile() {
409   DCHECK(!IsProxyMethod());
410   return GetDeclaringClass()->GetSourceFile();
411 }
412 
GetClassDefIndex()413 inline uint16_t ArtMethod::GetClassDefIndex() {
414   DCHECK(!IsProxyMethod());
415   return GetDeclaringClass()->GetDexClassDefIndex();
416 }
417 
GetClassDef()418 inline const DexFile::ClassDef& ArtMethod::GetClassDef() {
419   DCHECK(!IsProxyMethod());
420   return GetDexFile()->GetClassDef(GetClassDefIndex());
421 }
422 
GetReturnTypeDescriptor()423 inline const char* ArtMethod::GetReturnTypeDescriptor() {
424   DCHECK(!IsProxyMethod());
425   const DexFile* dex_file = GetDexFile();
426   const DexFile::MethodId& method_id = dex_file->GetMethodId(GetDexMethodIndex());
427   const DexFile::ProtoId& proto_id = dex_file->GetMethodPrototype(method_id);
428   uint16_t return_type_idx = proto_id.return_type_idx_;
429   return dex_file->GetTypeDescriptor(dex_file->GetTypeId(return_type_idx));
430 }
431 
GetTypeDescriptorFromTypeIdx(uint16_t type_idx)432 inline const char* ArtMethod::GetTypeDescriptorFromTypeIdx(uint16_t type_idx) {
433   DCHECK(!IsProxyMethod());
434   const DexFile* dex_file = GetDexFile();
435   return dex_file->GetTypeDescriptor(dex_file->GetTypeId(type_idx));
436 }
437 
GetClassLoader()438 inline mirror::ClassLoader* ArtMethod::GetClassLoader() {
439   DCHECK(!IsProxyMethod());
440   return GetDeclaringClass()->GetClassLoader();
441 }
442 
GetDexCache()443 inline mirror::DexCache* ArtMethod::GetDexCache() {
444   DCHECK(!IsProxyMethod());
445   return GetDeclaringClass()->GetDexCache();
446 }
447 
IsProxyMethod()448 inline bool ArtMethod::IsProxyMethod() {
449   return GetDeclaringClass()->IsProxyClass();
450 }
451 
GetInterfaceMethodIfProxy(size_t pointer_size)452 inline ArtMethod* ArtMethod::GetInterfaceMethodIfProxy(size_t pointer_size) {
453   if (LIKELY(!IsProxyMethod())) {
454     return this;
455   }
456   mirror::Class* klass = GetDeclaringClass();
457   auto interface_method = GetDexCacheResolvedMethods()->GetElementPtrSize<ArtMethod*>(
458       GetDexMethodIndex(), pointer_size);
459   DCHECK(interface_method != nullptr);
460   DCHECK_EQ(interface_method,
461             Runtime::Current()->GetClassLinker()->FindMethodForProxy(klass, this));
462   return interface_method;
463 }
464 
SetDexCacheResolvedMethods(mirror::PointerArray * new_dex_cache_methods)465 inline void ArtMethod::SetDexCacheResolvedMethods(mirror::PointerArray* new_dex_cache_methods) {
466   dex_cache_resolved_methods_ = GcRoot<mirror::PointerArray>(new_dex_cache_methods);
467 }
468 
SetDexCacheResolvedTypes(mirror::ObjectArray<mirror::Class> * new_dex_cache_types)469 inline void ArtMethod::SetDexCacheResolvedTypes(
470     mirror::ObjectArray<mirror::Class>* new_dex_cache_types) {
471   dex_cache_resolved_types_ = GcRoot<mirror::ObjectArray<mirror::Class>>(new_dex_cache_types);
472 }
473 
GetReturnType(bool resolve)474 inline mirror::Class* ArtMethod::GetReturnType(bool resolve) {
475   DCHECK(!IsProxyMethod());
476   const DexFile* dex_file = GetDexFile();
477   const DexFile::MethodId& method_id = dex_file->GetMethodId(GetDexMethodIndex());
478   const DexFile::ProtoId& proto_id = dex_file->GetMethodPrototype(method_id);
479   uint16_t return_type_idx = proto_id.return_type_idx_;
480   mirror::Class* type = GetDexCacheResolvedType(return_type_idx);
481   if (type == nullptr && resolve) {
482     type = Runtime::Current()->GetClassLinker()->ResolveType(return_type_idx, this);
483     CHECK(type != nullptr || Thread::Current()->IsExceptionPending());
484   }
485   return type;
486 }
487 
488 template<typename RootVisitorType>
VisitRoots(RootVisitorType & visitor)489 void ArtMethod::VisitRoots(RootVisitorType& visitor) {
490   visitor.VisitRootIfNonNull(declaring_class_.AddressWithoutBarrier());
491   visitor.VisitRootIfNonNull(dex_cache_resolved_methods_.AddressWithoutBarrier());
492   visitor.VisitRootIfNonNull(dex_cache_resolved_types_.AddressWithoutBarrier());
493 }
494 
CopyFrom(const ArtMethod * src,size_t image_pointer_size)495 inline void ArtMethod::CopyFrom(const ArtMethod* src, size_t image_pointer_size) {
496   memcpy(reinterpret_cast<void*>(this), reinterpret_cast<const void*>(src),
497          ObjectSize(image_pointer_size));
498   declaring_class_ = GcRoot<mirror::Class>(const_cast<ArtMethod*>(src)->GetDeclaringClass());
499   dex_cache_resolved_methods_ = GcRoot<mirror::PointerArray>(
500       const_cast<ArtMethod*>(src)->GetDexCacheResolvedMethods());
501   dex_cache_resolved_types_ = GcRoot<mirror::ObjectArray<mirror::Class>>(
502       const_cast<ArtMethod*>(src)->GetDexCacheResolvedTypes());
503 }
504 
505 }  // namespace art
506 
507 #endif  // ART_RUNTIME_ART_METHOD_INL_H_
508