/* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ART_RUNTIME_MIRROR_ABSTRACT_METHOD_H_ #define ART_RUNTIME_MIRROR_ABSTRACT_METHOD_H_ #include "class.h" #include "dex_file.h" #include "invoke_type.h" #include "locks.h" #include "modifiers.h" #include "object.h" namespace art { struct AbstractMethodOffsets; struct ConstructorMethodOffsets; union JValue; struct MethodClassOffsets; class MethodHelper; struct MethodOffsets; class StringPiece; class ShadowFrame; namespace mirror { class StaticStorageBase; typedef void (EntryPointFromInterpreter)(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item, ShadowFrame* shadow_frame, JValue* result); // C++ mirror of java.lang.reflect.Method and java.lang.reflect.Constructor class MANAGED AbstractMethod : public Object { public: Class* GetDeclaringClass() const; void SetDeclaringClass(Class *new_declaring_class) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); static MemberOffset DeclaringClassOffset() { return MemberOffset(OFFSETOF_MEMBER(AbstractMethod, declaring_class_)); } static MemberOffset EntryPointFromCompiledCodeOffset() { return MemberOffset(OFFSETOF_MEMBER(AbstractMethod, entry_point_from_compiled_code_)); } uint32_t GetAccessFlags() const; void SetAccessFlags(uint32_t new_access_flags) { SetField32(OFFSET_OF_OBJECT_MEMBER(AbstractMethod, access_flags_), new_access_flags, false); } // Approximate what kind of method call would be used for this method. InvokeType GetInvokeType() const; // Returns true if the method is declared public. bool IsPublic() const { return (GetAccessFlags() & kAccPublic) != 0; } // Returns true if the method is declared private. bool IsPrivate() const { return (GetAccessFlags() & kAccPrivate) != 0; } // Returns true if the method is declared static. bool IsStatic() const { return (GetAccessFlags() & kAccStatic) != 0; } // Returns true if the method is a constructor. bool IsConstructor() const { return (GetAccessFlags() & kAccConstructor) != 0; } // Returns true if the method is static, private, or a constructor. bool IsDirect() const { return IsDirect(GetAccessFlags()); } static bool IsDirect(uint32_t access_flags) { return (access_flags & (kAccStatic | kAccPrivate | kAccConstructor)) != 0; } // Returns true if the method is declared synchronized. bool IsSynchronized() const { uint32_t synchonized = kAccSynchronized | kAccDeclaredSynchronized; return (GetAccessFlags() & synchonized) != 0; } bool IsFinal() const { return (GetAccessFlags() & kAccFinal) != 0; } bool IsMiranda() const { return (GetAccessFlags() & kAccMiranda) != 0; } bool IsNative() const { return (GetAccessFlags() & kAccNative) != 0; } bool IsAbstract() const { return (GetAccessFlags() & kAccAbstract) != 0; } bool IsSynthetic() const { return (GetAccessFlags() & kAccSynthetic) != 0; } bool IsProxyMethod() const; bool IsPreverified() const { return (GetAccessFlags() & kAccPreverified) != 0; } void SetPreverified() { SetAccessFlags(GetAccessFlags() | kAccPreverified); } bool CheckIncompatibleClassChange(InvokeType type) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); uint16_t GetMethodIndex() const; size_t GetVtableIndex() const { return GetMethodIndex(); } void SetMethodIndex(uint16_t new_method_index) { SetField32(OFFSET_OF_OBJECT_MEMBER(AbstractMethod, method_index_), new_method_index, false); } static MemberOffset MethodIndexOffset() { return OFFSET_OF_OBJECT_MEMBER(AbstractMethod, method_index_); } uint32_t GetCodeItemOffset() const { return GetField32(OFFSET_OF_OBJECT_MEMBER(AbstractMethod, code_item_offset_), false); } void SetCodeItemOffset(uint32_t new_code_off) { SetField32(OFFSET_OF_OBJECT_MEMBER(AbstractMethod, code_item_offset_), new_code_off, false); } // Number of 32bit registers that would be required to hold all the arguments static size_t NumArgRegisters(const StringPiece& shorty); uint32_t GetDexMethodIndex() const; void SetDexMethodIndex(uint32_t new_idx) { SetField32(OFFSET_OF_OBJECT_MEMBER(AbstractMethod, method_dex_index_), new_idx, false); } ObjectArray* GetDexCacheStrings() const; void SetDexCacheStrings(ObjectArray* new_dex_cache_strings) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); static MemberOffset DexCacheStringsOffset() { return OFFSET_OF_OBJECT_MEMBER(AbstractMethod, dex_cache_strings_); } static MemberOffset DexCacheResolvedMethodsOffset() { return OFFSET_OF_OBJECT_MEMBER(AbstractMethod, dex_cache_resolved_methods_); } static MemberOffset DexCacheResolvedTypesOffset() { return OFFSET_OF_OBJECT_MEMBER(AbstractMethod, dex_cache_resolved_types_); } static MemberOffset DexCacheInitializedStaticStorageOffset() { return OFFSET_OF_OBJECT_MEMBER(AbstractMethod, dex_cache_initialized_static_storage_); } ObjectArray* GetDexCacheResolvedMethods() const; void SetDexCacheResolvedMethods(ObjectArray* new_dex_cache_methods) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); ObjectArray* GetDexCacheResolvedTypes() const; void SetDexCacheResolvedTypes(ObjectArray* new_dex_cache_types) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); ObjectArray* GetDexCacheInitializedStaticStorage() const; void SetDexCacheInitializedStaticStorage(ObjectArray* new_value) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Find the method that this method overrides AbstractMethod* FindOverriddenMethod() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void Invoke(Thread* self, uint32_t* args, uint32_t args_size, JValue* result, char result_type) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); EntryPointFromInterpreter* GetEntryPointFromInterpreter() const { return GetFieldPtr(OFFSET_OF_OBJECT_MEMBER(AbstractMethod, entry_point_from_interpreter_), false); } void SetEntryPointFromInterpreter(EntryPointFromInterpreter* entry_point_from_interpreter) { SetFieldPtr(OFFSET_OF_OBJECT_MEMBER(AbstractMethod, entry_point_from_interpreter_), entry_point_from_interpreter, false); } const void* GetEntryPointFromCompiledCode() const { return GetFieldPtr(OFFSET_OF_OBJECT_MEMBER(AbstractMethod, entry_point_from_compiled_code_), false); } void SetEntryPointFromCompiledCode(const void* entry_point_from_compiled_code) { SetFieldPtr(OFFSET_OF_OBJECT_MEMBER(AbstractMethod, entry_point_from_compiled_code_), entry_point_from_compiled_code, false); } uint32_t GetCodeSize() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); bool IsWithinCode(uintptr_t pc) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { uintptr_t code = reinterpret_cast(GetEntryPointFromCompiledCode()); if (code == 0) { return pc == 0; } /* * During a stack walk, a return PC may point to the end of the code + 1 * (in the case that the last instruction is a call that isn't expected to * return. Thus, we check <= code + GetCodeSize(). */ return (code <= pc && pc <= code + GetCodeSize()); } void AssertPcIsWithinCode(uintptr_t pc) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); uint32_t GetOatCodeOffset() const; void SetOatCodeOffset(uint32_t code_offset); static MemberOffset GetEntryPointFromCompiledCodeOffset() { return OFFSET_OF_OBJECT_MEMBER(AbstractMethod, entry_point_from_compiled_code_); } const uint32_t* GetMappingTable() const { const uint32_t* map = GetMappingTableRaw(); if (map == NULL) { return map; } return map + 1; } uint32_t GetPcToDexMappingTableLength() const { const uint32_t* map = GetMappingTableRaw(); if (map == NULL) { return 0; } return map[2]; } const uint32_t* GetPcToDexMappingTable() const { const uint32_t* map = GetMappingTableRaw(); if (map == NULL) { return map; } return map + 3; } uint32_t GetDexToPcMappingTableLength() const { const uint32_t* map = GetMappingTableRaw(); if (map == NULL) { return 0; } return map[1] - map[2]; } const uint32_t* GetDexToPcMappingTable() const { const uint32_t* map = GetMappingTableRaw(); if (map == NULL) { return map; } return map + 3 + map[2]; } const uint32_t* GetMappingTableRaw() const { return GetFieldPtr(OFFSET_OF_OBJECT_MEMBER(AbstractMethod, mapping_table_), false); } void SetMappingTable(const uint32_t* mapping_table) { SetFieldPtr(OFFSET_OF_OBJECT_MEMBER(AbstractMethod, mapping_table_), mapping_table, false); } uint32_t GetOatMappingTableOffset() const; void SetOatMappingTableOffset(uint32_t mapping_table_offset); // Callers should wrap the uint16_t* in a VmapTable instance for convenient access. const uint16_t* GetVmapTableRaw() const { return GetFieldPtr(OFFSET_OF_OBJECT_MEMBER(AbstractMethod, vmap_table_), false); } void SetVmapTable(const uint16_t* vmap_table) { SetFieldPtr(OFFSET_OF_OBJECT_MEMBER(AbstractMethod, vmap_table_), vmap_table, false); } uint32_t GetOatVmapTableOffset() const; void SetOatVmapTableOffset(uint32_t vmap_table_offset); const uint8_t* GetNativeGcMap() const { return GetFieldPtr(OFFSET_OF_OBJECT_MEMBER(AbstractMethod, gc_map_), false); } void SetNativeGcMap(const uint8_t* data) { SetFieldPtr(OFFSET_OF_OBJECT_MEMBER(AbstractMethod, gc_map_), data, false); } // When building the oat need a convenient place to stuff the offset of the native GC map. void SetOatNativeGcMapOffset(uint32_t gc_map_offset); uint32_t GetOatNativeGcMapOffset() const; size_t GetFrameSizeInBytes() const { DCHECK_EQ(sizeof(size_t), sizeof(uint32_t)); size_t result = GetField32(OFFSET_OF_OBJECT_MEMBER(AbstractMethod, frame_size_in_bytes_), false); DCHECK_LE(static_cast(kStackAlignment), result); return result; } void SetFrameSizeInBytes(size_t new_frame_size_in_bytes) { DCHECK_EQ(sizeof(size_t), sizeof(uint32_t)); SetField32(OFFSET_OF_OBJECT_MEMBER(AbstractMethod, frame_size_in_bytes_), new_frame_size_in_bytes, false); } size_t GetReturnPcOffsetInBytes() const { return GetFrameSizeInBytes() - kPointerSize; } size_t GetSirtOffsetInBytes() const { CHECK(IsNative()); return kPointerSize; } bool IsRegistered() const; void RegisterNative(Thread* self, const void* native_method) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void UnregisterNative(Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); static MemberOffset NativeMethodOffset() { return OFFSET_OF_OBJECT_MEMBER(AbstractMethod, native_method_); } const void* GetNativeMethod() const { return reinterpret_cast(GetField32(NativeMethodOffset(), false)); } void SetNativeMethod(const void*); static MemberOffset GetMethodIndexOffset() { return OFFSET_OF_OBJECT_MEMBER(AbstractMethod, method_index_); } uint32_t GetCoreSpillMask() const { return GetField32(OFFSET_OF_OBJECT_MEMBER(AbstractMethod, core_spill_mask_), false); } void SetCoreSpillMask(uint32_t core_spill_mask) { // Computed during compilation SetField32(OFFSET_OF_OBJECT_MEMBER(AbstractMethod, core_spill_mask_), core_spill_mask, false); } uint32_t GetFpSpillMask() const { return GetField32(OFFSET_OF_OBJECT_MEMBER(AbstractMethod, fp_spill_mask_), false); } void SetFpSpillMask(uint32_t fp_spill_mask) { // Computed during compilation SetField32(OFFSET_OF_OBJECT_MEMBER(AbstractMethod, fp_spill_mask_), fp_spill_mask, false); } // Is this a CalleSaveMethod or ResolutionMethod and therefore doesn't adhere to normal // conventions for a method of managed code. Returns false for Proxy methods. bool IsRuntimeMethod() const; // Is this a hand crafted method used for something like describing callee saves? bool IsCalleeSaveMethod() const; bool IsResolutionMethod() const; uintptr_t NativePcOffset(const uintptr_t pc) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Converts a native PC to a dex PC. uint32_t ToDexPc(const uintptr_t pc) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Converts a dex PC to a native PC. uintptr_t ToNativePc(const uint32_t dex_pc) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Converts a dex PC to the first corresponding safepoint PC. uintptr_t ToFirstNativeSafepointPc(const uint32_t dex_pc) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Find the catch block for the given exception type and dex_pc uint32_t FindCatchBlock(Class* exception_type, uint32_t dex_pc) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); static void SetClasses(Class* java_lang_reflect_Constructor, Class* java_lang_reflect_Method); static Class* GetConstructorClass() { return java_lang_reflect_Constructor_; } static Class* GetMethodClass() { return java_lang_reflect_Method_; } static void ResetClasses(); protected: // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses". // The class we are a part of Class* declaring_class_; // short cuts to declaring_class_->dex_cache_ member for fast compiled code access ObjectArray* dex_cache_initialized_static_storage_; // short cuts to declaring_class_->dex_cache_ member for fast compiled code access ObjectArray* dex_cache_resolved_methods_; // short cuts to declaring_class_->dex_cache_ member for fast compiled code access ObjectArray* dex_cache_resolved_types_; // short cuts to declaring_class_->dex_cache_ member for fast compiled code access ObjectArray* dex_cache_strings_; // Access flags; low 16 bits are defined by spec. uint32_t access_flags_; // Offset to the CodeItem. uint32_t code_item_offset_; // Architecture-dependent register spill mask uint32_t core_spill_mask_; // Compiled code associated with this method for callers from managed code. // May be compiled managed code or a bridge for invoking a native method. // TODO: Break apart this into portable and quick. const void* entry_point_from_compiled_code_; // Called by the interpreter to execute this method. EntryPointFromInterpreter* entry_point_from_interpreter_; // Architecture-dependent register spill mask uint32_t fp_spill_mask_; // Total size in bytes of the frame size_t frame_size_in_bytes_; // Garbage collection map of native PC offsets (quick) or dex PCs (portable) to reference bitmaps. const uint8_t* gc_map_; // Mapping from native pc to dex pc const uint32_t* mapping_table_; // Index into method_ids of the dex file associated with this method uint32_t method_dex_index_; // For concrete virtual methods, this is the offset of the method in Class::vtable_. // // For abstract methods in an interface class, this is the offset of the method in // "iftable_->Get(n)->GetMethodArray()". // // For static and direct methods this is the index in the direct methods table. uint32_t method_index_; // The target native method registered with this method const void* native_method_; // When a register is promoted into a register, the spill mask holds which registers hold dex // registers. The first promoted register's corresponding dex register is vmap_table_[1], the Nth // is vmap_table_[N]. vmap_table_[0] holds the length of the table. const uint16_t* vmap_table_; static Class* java_lang_reflect_Constructor_; static Class* java_lang_reflect_Method_; friend struct art::AbstractMethodOffsets; // for verifying offset information friend struct art::ConstructorMethodOffsets; // for verifying offset information friend struct art::MethodOffsets; // for verifying offset information DISALLOW_IMPLICIT_CONSTRUCTORS(AbstractMethod); }; class MANAGED Method : public AbstractMethod { }; class MANAGED Constructor : public AbstractMethod { }; class MANAGED AbstractMethodClass : public Class { private: Object* ORDER_BY_SIGNATURE_; friend struct art::MethodClassOffsets; // for verifying offset information DISALLOW_IMPLICIT_CONSTRUCTORS(AbstractMethodClass); }; } // namespace mirror } // namespace art #endif // ART_RUNTIME_MIRROR_ABSTRACT_METHOD_H_