Merge "Remove warning when we do too many simplifications"
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index 8c61871..e0f0ae5 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -61,7 +61,7 @@
# Dex file dependencies for each gtest.
ART_GTEST_class_linker_test_DEX_DEPS := Interfaces MultiDex MyClass Nested Statics StaticsFromCode
-ART_GTEST_compiler_driver_test_DEX_DEPS := AbstractMethod
+ART_GTEST_compiler_driver_test_DEX_DEPS := AbstractMethod StaticLeafMethods
ART_GTEST_dex_file_test_DEX_DEPS := GetMethodSignature Main Nested
ART_GTEST_exception_test_DEX_DEPS := ExceptionHandle
ART_GTEST_jni_compiler_test_DEX_DEPS := MyClassNatives
diff --git a/compiler/cfi_test.h b/compiler/cfi_test.h
index cdb1b9e..f7501d2 100644
--- a/compiler/cfi_test.h
+++ b/compiler/cfi_test.h
@@ -22,6 +22,7 @@
#include <sstream>
#include "arch/instruction_set.h"
+#include "dwarf/dwarf_constants.h"
#include "dwarf/dwarf_test.h"
#include "dwarf/headers.h"
#include "disassembler/disassembler.h"
@@ -45,7 +46,8 @@
// Pretty-print CFI opcodes.
constexpr bool is64bit = false;
dwarf::DebugFrameOpCodeWriter<> initial_opcodes;
- dwarf::WriteEhFrameCIE(is64bit, dwarf::Reg(8), initial_opcodes, &eh_frame_data_);
+ dwarf::WriteEhFrameCIE(is64bit, dwarf::DW_EH_PE_absptr, dwarf::Reg(8),
+ initial_opcodes, &eh_frame_data_);
std::vector<uintptr_t> eh_frame_patches;
dwarf::WriteEhFrameFDE(is64bit, 0, 0, actual_asm.size(), &actual_cfi,
&eh_frame_data_, &eh_frame_patches);
diff --git a/compiler/common_compiler_test.cc b/compiler/common_compiler_test.cc
index 8ffc86e..05cb8b4 100644
--- a/compiler/common_compiler_test.cc
+++ b/compiler/common_compiler_test.cc
@@ -140,6 +140,27 @@
}
}
+// Get the set of image classes given to the compiler-driver in SetUp. Note: the compiler
+// driver assumes ownership of the set, so the test should properly release the set.
+std::unordered_set<std::string>* CommonCompilerTest::GetImageClasses() {
+ // Empty set: by default no classes are retained in the image.
+ return new std::unordered_set<std::string>();
+}
+
+// Get the set of compiled classes given to the compiler-driver in SetUp. Note: the compiler
+// driver assumes ownership of the set, so the test should properly release the set.
+std::unordered_set<std::string>* CommonCompilerTest::GetCompiledClasses() {
+ // Null, no selection of compiled-classes.
+ return nullptr;
+}
+
+// Get the set of compiled methods given to the compiler-driver in SetUp. Note: the compiler
+// driver assumes ownership of the set, so the test should properly release the set.
+std::unordered_set<std::string>* CommonCompilerTest::GetCompiledMethods() {
+ // Null, no selection of compiled-methods.
+ return nullptr;
+}
+
void CommonCompilerTest::SetUp() {
CommonRuntimeTest::SetUp();
{
@@ -165,7 +186,10 @@
method_inliner_map_.get(),
compiler_kind, instruction_set,
instruction_set_features_.get(),
- true, new std::unordered_set<std::string>, nullptr,
+ true,
+ GetImageClasses(),
+ GetCompiledClasses(),
+ GetCompiledMethods(),
2, true, true, "", timer_.get(), -1, ""));
}
// We typically don't generate an image in unit tests, disable this optimization by default.
diff --git a/compiler/common_compiler_test.h b/compiler/common_compiler_test.h
index d7b210d..8d80a2d 100644
--- a/compiler/common_compiler_test.h
+++ b/compiler/common_compiler_test.h
@@ -18,6 +18,7 @@
#define ART_COMPILER_COMMON_COMPILER_TEST_H_
#include <list>
+#include <unordered_set>
#include <vector>
#include "common_runtime_test.h"
@@ -56,6 +57,18 @@
virtual void SetUpRuntimeOptions(RuntimeOptions *options);
+ // Get the set of image classes given to the compiler-driver in SetUp. Note: the compiler
+ // driver assumes ownership of the set, so the test should properly release the set.
+ virtual std::unordered_set<std::string>* GetImageClasses();
+
+ // Get the set of compiled classes given to the compiler-driver in SetUp. Note: the compiler
+ // driver assumes ownership of the set, so the test should properly release the set.
+ virtual std::unordered_set<std::string>* GetCompiledClasses();
+
+ // Get the set of compiled methods given to the compiler-driver in SetUp. Note: the compiler
+ // driver assumes ownership of the set, so the test should properly release the set.
+ virtual std::unordered_set<std::string>* GetCompiledMethods();
+
virtual void TearDown();
void CompileClass(mirror::ClassLoader* class_loader, const char* class_name)
diff --git a/compiler/dex/quick/quick_cfi_test.cc b/compiler/dex/quick/quick_cfi_test.cc
index d276457..555d5b9 100644
--- a/compiler/dex/quick/quick_cfi_test.cc
+++ b/compiler/dex/quick/quick_cfi_test.cc
@@ -76,7 +76,7 @@
isa_features.reset(InstructionSetFeatures::FromVariant(isa, "default", &error));
CompilerDriver driver(&compiler_options, &verification_results, &method_inliner_map,
Compiler::kQuick, isa, isa_features.get(),
- false, 0, 0, 0, false, false, "", 0, -1, "");
+ false, nullptr, nullptr, nullptr, 0, false, false, "", 0, -1, "");
ClassLinker* linker = nullptr;
CompilationUnit cu(&pool, isa, &driver, linker);
DexFile::CodeItem code_item { 0, 0, 0, 0, 0, 0, { 0 } }; // NOLINT
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 1832647..e665e1d 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -76,8 +76,8 @@
// Whether to produce 64-bit ELF files for 64-bit targets. Leave this off for now.
static constexpr bool kProduce64BitELFFiles = false;
-// Whether classes-to-compile is only applied to the boot image, or, when given, too all
-// compilations.
+// Whether classes-to-compile and methods-to-compile are only applied to the boot image, or, when
+// given, too all compilations.
static constexpr bool kRestrictCompilationFiltersToImage = true;
static double Percentage(size_t x, size_t y) {
@@ -349,6 +349,7 @@
const InstructionSetFeatures* instruction_set_features,
bool image, std::unordered_set<std::string>* image_classes,
std::unordered_set<std::string>* compiled_classes,
+ std::unordered_set<std::string>* compiled_methods,
size_t thread_count, bool dump_stats, bool dump_passes,
const std::string& dump_cfg_file_name, CumulativeLogger* timer,
int swap_fd, const std::string& profile_file)
@@ -369,6 +370,7 @@
image_(image),
image_classes_(image_classes),
classes_to_compile_(compiled_classes),
+ methods_to_compile_(compiled_methods),
had_hard_verifier_failure_(false),
thread_count_(thread_count),
stats_(new AOTCompilationStats),
@@ -670,6 +672,19 @@
return classes_to_compile_->find(descriptor) != classes_to_compile_->end();
}
+bool CompilerDriver::IsMethodToCompile(const MethodReference& method_ref) const {
+ if (kRestrictCompilationFiltersToImage && !IsImage()) {
+ return true;
+ }
+
+ if (methods_to_compile_ == nullptr) {
+ return true;
+ }
+
+ std::string tmp = PrettyMethod(method_ref.dex_method_index, *method_ref.dex_file, true);
+ return methods_to_compile_->find(tmp.c_str()) != methods_to_compile_->end();
+}
+
static void ResolveExceptionsForMethod(MutableHandle<mirror::ArtMethod> method_handle,
std::set<std::pair<uint16_t, const DexFile*>>& exceptions_to_resolve)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
@@ -2232,7 +2247,9 @@
// Basic checks, e.g., not <clinit>.
verification_results_->IsCandidateForCompilation(method_ref, access_flags) &&
// Did not fail to create VerifiedMethod metadata.
- has_verified_method;
+ has_verified_method &&
+ // Is eligable for compilation by methods-to-compile filter.
+ IsMethodToCompile(method_ref);
if (compile) {
// NOTE: if compiler declines to compile this method, it will return nullptr.
compiled_method = compiler_->Compile(code_item, access_flags, invoke_type, class_def_idx,
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index ce13a17..50e1fb1 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -104,6 +104,7 @@
const InstructionSetFeatures* instruction_set_features,
bool image, std::unordered_set<std::string>* image_classes,
std::unordered_set<std::string>* compiled_classes,
+ std::unordered_set<std::string>* compiled_methods,
size_t thread_count, bool dump_stats, bool dump_passes,
const std::string& dump_cfg_file_name,
CumulativeLogger* timer, int swap_fd,
@@ -428,6 +429,9 @@
// Checks whether the provided class should be compiled, i.e., is in classes_to_compile_.
bool IsClassToCompile(const char* descriptor) const;
+ // Checks whether the provided method should be compiled, i.e., is in method_to_compile_.
+ bool IsMethodToCompile(const MethodReference& method_ref) const;
+
void RecordClassStatus(ClassReference ref, mirror::Class::Status status)
LOCKS_EXCLUDED(compiled_classes_lock_);
@@ -597,6 +601,11 @@
// This option may be restricted to the boot image, depending on a flag in the implementation.
std::unique_ptr<std::unordered_set<std::string>> classes_to_compile_;
+ // Specifies the methods that will be compiled. Note that if methods_to_compile_ is nullptr,
+ // all methods are eligible for compilation (compilation filters etc. will still apply).
+ // This option may be restricted to the boot image, depending on a flag in the implementation.
+ std::unique_ptr<std::unordered_set<std::string>> methods_to_compile_;
+
bool had_hard_verifier_failure_;
size_t thread_count_;
diff --git a/compiler/driver/compiler_driver_test.cc b/compiler/driver/compiler_driver_test.cc
index e78ff90..ded50ca 100644
--- a/compiler/driver/compiler_driver_test.cc
+++ b/compiler/driver/compiler_driver_test.cc
@@ -175,6 +175,60 @@
}
}
+class CompilerDriverMethodsTest : public CompilerDriverTest {
+ protected:
+ std::unordered_set<std::string>* GetCompiledMethods() OVERRIDE {
+ return new std::unordered_set<std::string>({
+ "byte StaticLeafMethods.identity(byte)",
+ "int StaticLeafMethods.sum(int, int, int)",
+ "double StaticLeafMethods.sum(double, double, double, double)"
+ });
+ }
+};
+
+TEST_F(CompilerDriverMethodsTest, Selection) {
+ Thread* self = Thread::Current();
+ jobject class_loader;
+ {
+ ScopedObjectAccess soa(self);
+ class_loader = LoadDex("StaticLeafMethods");
+ }
+ ASSERT_NE(class_loader, nullptr);
+
+ // Need to enable dex-file writability. Methods rejected to be compiled will run through the
+ // dex-to-dex compiler.
+ for (const DexFile* dex_file : GetDexFiles(class_loader)) {
+ ASSERT_TRUE(dex_file->EnableWrite());
+ }
+
+ CompileAll(class_loader);
+
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ StackHandleScope<1> hs(self);
+ ScopedObjectAccess soa(self);
+ Handle<mirror::ClassLoader> h_loader(hs.NewHandle(
+ reinterpret_cast<mirror::ClassLoader*>(self->DecodeJObject(class_loader))));
+ mirror::Class* klass = class_linker->FindClass(self, "LStaticLeafMethods;", h_loader);
+ ASSERT_NE(klass, nullptr);
+
+ std::unique_ptr<std::unordered_set<std::string>> expected(GetCompiledMethods());
+
+ for (int32_t i = 0; static_cast<uint32_t>(i) < klass->NumDirectMethods(); i++) {
+ mirror::ArtMethod* m = klass->GetDirectMethod(i);
+ std::string name = PrettyMethod(m, true);
+ const void* code =
+ m->GetEntryPointFromQuickCompiledCodePtrSize(InstructionSetPointerSize(kRuntimeISA));
+ ASSERT_NE(code, nullptr);
+ if (expected->find(name) != expected->end()) {
+ expected->erase(name);
+ EXPECT_FALSE(class_linker->IsQuickToInterpreterBridge(code));
+ } else {
+ EXPECT_TRUE(class_linker->IsQuickToInterpreterBridge(code));
+ }
+ }
+ EXPECT_TRUE(expected->empty());
+}
+
// TODO: need check-cast test (when stub complete & we can throw/catch
} // namespace art
diff --git a/compiler/dwarf/dwarf_constants.h b/compiler/dwarf/dwarf_constants.h
index 8e39ca7..61a44cd 100644
--- a/compiler/dwarf/dwarf_constants.h
+++ b/compiler/dwarf/dwarf_constants.h
@@ -658,6 +658,28 @@
DW_CFA_hi_user = 0x3f
};
+enum ExceptionHeaderValueFormat : uint8_t {
+ DW_EH_PE_native = 0x00,
+ DW_EH_PE_uleb128 = 0x01,
+ DW_EH_PE_udata2 = 0x02,
+ DW_EH_PE_udata4 = 0x03,
+ DW_EH_PE_udata8 = 0x04,
+ DW_EH_PE_sleb128 = 0x09,
+ DW_EH_PE_sdata2 = 0x0A,
+ DW_EH_PE_sdata4 = 0x0B,
+ DW_EH_PE_sdata8 = 0x0C,
+ DW_EH_PE_omit = 0xFF,
+};
+
+enum ExceptionHeaderValueApplication : uint8_t {
+ DW_EH_PE_absptr = 0x00,
+ DW_EH_PE_pcrel = 0x10,
+ DW_EH_PE_textrel = 0x20,
+ DW_EH_PE_datarel = 0x30,
+ DW_EH_PE_funcrel = 0x40,
+ DW_EH_PE_aligned = 0x50,
+};
+
} // namespace dwarf
} // namespace art
diff --git a/compiler/dwarf/dwarf_test.cc b/compiler/dwarf/dwarf_test.cc
index 98f691a..edba00a 100644
--- a/compiler/dwarf/dwarf_test.cc
+++ b/compiler/dwarf/dwarf_test.cc
@@ -16,6 +16,7 @@
#include "dwarf_test.h"
+#include "dwarf/dwarf_constants.h"
#include "dwarf/debug_frame_opcode_writer.h"
#include "dwarf/debug_info_entry_writer.h"
#include "dwarf/debug_line_opcode_writer.h"
@@ -119,7 +120,8 @@
DW_CHECK_NEXT("DW_CFA_restore: r5 (ebp)");
DebugFrameOpCodeWriter<> initial_opcodes;
- WriteEhFrameCIE(is64bit, Reg(is64bit ? 16 : 8), initial_opcodes, &eh_frame_data_);
+ WriteEhFrameCIE(is64bit, DW_EH_PE_absptr, Reg(is64bit ? 16 : 8),
+ initial_opcodes, &eh_frame_data_);
std::vector<uintptr_t> eh_frame_patches;
std::vector<uintptr_t> expected_patches { 28 }; // NOLINT
WriteEhFrameFDE(is64bit, 0, 0x01000000, 0x01000000, opcodes.data(),
@@ -132,7 +134,8 @@
TEST_F(DwarfTest, DebugFrame64) {
constexpr bool is64bit = true;
DebugFrameOpCodeWriter<> initial_opcodes;
- WriteEhFrameCIE(is64bit, Reg(16), initial_opcodes, &eh_frame_data_);
+ WriteEhFrameCIE(is64bit, DW_EH_PE_absptr, Reg(16),
+ initial_opcodes, &eh_frame_data_);
DebugFrameOpCodeWriter<> opcodes;
std::vector<uintptr_t> eh_frame_patches;
std::vector<uintptr_t> expected_patches { 32 }; // NOLINT
@@ -170,7 +173,8 @@
DW_CHECK_NEXT("DW_CFA_offset: r14 (r14)");
DW_CHECK_NEXT("DW_CFA_offset: r15 (r15)");
DebugFrameOpCodeWriter<> initial_opcodes;
- WriteEhFrameCIE(is64bit, Reg(16), initial_opcodes, &eh_frame_data_);
+ WriteEhFrameCIE(is64bit, DW_EH_PE_absptr, Reg(16),
+ initial_opcodes, &eh_frame_data_);
std::vector<uintptr_t> eh_frame_patches;
WriteEhFrameFDE(is64bit, 0, 0x0100000000000000, 0x0200000000000000,
opcodes.data(), &eh_frame_data_, &eh_frame_patches);
diff --git a/compiler/dwarf/dwarf_test.h b/compiler/dwarf/dwarf_test.h
index 5a97c3b..d31cfa5 100644
--- a/compiler/dwarf/dwarf_test.h
+++ b/compiler/dwarf/dwarf_test.h
@@ -70,30 +70,30 @@
Elf_Sym, Elf_Ehdr, Elf_Phdr, Elf_Shdr> builder(
&code, file.GetFile(), isa, 0, 0, 0, 0, 0, 0, false, false);
typedef ElfRawSectionBuilder<Elf_Word, Elf_Sword, Elf_Shdr> Section;
+ Section debug_info(".debug_info", SHT_PROGBITS, 0, nullptr, 0, 1, 0);
+ Section debug_abbrev(".debug_abbrev", SHT_PROGBITS, 0, nullptr, 0, 1, 0);
+ Section debug_str(".debug_str", SHT_PROGBITS, 0, nullptr, 0, 1, 0);
+ Section debug_line(".debug_line", SHT_PROGBITS, 0, nullptr, 0, 1, 0);
+ Section eh_frame(".eh_frame", SHT_PROGBITS, SHF_ALLOC, nullptr, 0, 4, 0);
if (!debug_info_data_.empty()) {
- Section debug_info(".debug_info", SHT_PROGBITS, 0, nullptr, 0, 1, 0);
debug_info.SetBuffer(debug_info_data_);
- builder.RegisterRawSection(debug_info);
+ builder.RegisterRawSection(&debug_info);
}
if (!debug_abbrev_data_.empty()) {
- Section debug_abbrev(".debug_abbrev", SHT_PROGBITS, 0, nullptr, 0, 1, 0);
debug_abbrev.SetBuffer(debug_abbrev_data_);
- builder.RegisterRawSection(debug_abbrev);
+ builder.RegisterRawSection(&debug_abbrev);
}
if (!debug_str_data_.empty()) {
- Section debug_str(".debug_str", SHT_PROGBITS, 0, nullptr, 0, 1, 0);
debug_str.SetBuffer(debug_str_data_);
- builder.RegisterRawSection(debug_str);
+ builder.RegisterRawSection(&debug_str);
}
if (!debug_line_data_.empty()) {
- Section debug_line(".debug_line", SHT_PROGBITS, 0, nullptr, 0, 1, 0);
debug_line.SetBuffer(debug_line_data_);
- builder.RegisterRawSection(debug_line);
+ builder.RegisterRawSection(&debug_line);
}
if (!eh_frame_data_.empty()) {
- Section eh_frame(".eh_frame", SHT_PROGBITS, SHF_ALLOC, nullptr, 0, 4, 0);
eh_frame.SetBuffer(eh_frame_data_);
- builder.RegisterRawSection(eh_frame);
+ builder.RegisterRawSection(&eh_frame);
}
builder.Init();
builder.Write();
diff --git a/compiler/dwarf/headers.h b/compiler/dwarf/headers.h
index 760f53c..9f64766 100644
--- a/compiler/dwarf/headers.h
+++ b/compiler/dwarf/headers.h
@@ -22,6 +22,7 @@
#include "dwarf/debug_frame_opcode_writer.h"
#include "dwarf/debug_info_entry_writer.h"
#include "dwarf/debug_line_opcode_writer.h"
+#include "dwarf/dwarf_constants.h"
#include "dwarf/register.h"
#include "dwarf/writer.h"
@@ -36,7 +37,9 @@
// Write common information entry (CIE) to .eh_frame section.
template<typename Allocator>
-void WriteEhFrameCIE(bool is64bit, Reg return_address_register,
+void WriteEhFrameCIE(bool is64bit,
+ ExceptionHeaderValueApplication address_type,
+ Reg return_address_register,
const DebugFrameOpCodeWriter<Allocator>& opcodes,
std::vector<uint8_t>* eh_frame) {
Writer<> writer(eh_frame);
@@ -50,9 +53,9 @@
writer.PushUleb128(return_address_register.num()); // ubyte in DWARF2.
writer.PushUleb128(1); // z: Augmentation data size.
if (is64bit) {
- writer.PushUint8(0x04); // R: ((DW_EH_PE_absptr << 4) | DW_EH_PE_udata8).
+ writer.PushUint8(address_type | DW_EH_PE_udata8); // R: Pointer encoding.
} else {
- writer.PushUint8(0x03); // R: ((DW_EH_PE_absptr << 4) | DW_EH_PE_udata4).
+ writer.PushUint8(address_type | DW_EH_PE_udata4); // R: Pointer encoding.
}
writer.PushData(opcodes.data());
writer.Pad(is64bit ? 8 : 4);
diff --git a/compiler/elf_builder.h b/compiler/elf_builder.h
index 124ed03..323c933 100644
--- a/compiler/elf_builder.h
+++ b/compiler/elf_builder.h
@@ -584,11 +584,12 @@
// | Elf_Ehdr |
// +-------------------------+
// | Elf_Phdr PHDR |
- // | Elf_Phdr LOAD R | .dynsym .dynstr .hash .rodata
+ // | Elf_Phdr LOAD R | .dynsym .dynstr .hash .eh_frame .eh_frame_hdr .rodata
// | Elf_Phdr LOAD R X | .text
// | Elf_Phdr LOAD RW | .bss (Optional)
// | Elf_Phdr LOAD RW | .dynamic
// | Elf_Phdr DYNAMIC | .dynamic
+ // | Elf_Phdr EH_FRAME R | .eh_frame_hdr
// +-------------------------+
// | .dynsym |
// | Elf_Sym STN_UNDEF |
@@ -615,6 +616,10 @@
// | ... |
// | Elf_Word chain[c - 1] |
// +-------------------------+
+ // | .eh_frame | (Optional)
+ // +-------------------------+
+ // | .eh_frame_hdr | (Optional)
+ // +-------------------------+
// | .rodata |
// | oatdata..oatexec-4 |
// +-------------------------+
@@ -648,22 +653,21 @@
// | .shstrtab\0 |
// | .symtab\0 | (Optional)
// | .strtab\0 | (Optional)
- // | .debug_str\0 | (Optional)
- // | .debug_info\0 | (Optional)
// | .eh_frame\0 | (Optional)
- // | .debug_line\0 | (Optional)
+ // | .eh_frame_hdr\0 | (Optional)
+ // | .debug_info\0 | (Optional)
// | .debug_abbrev\0 | (Optional)
+ // | .debug_str\0 | (Optional)
+ // | .debug_line\0 | (Optional)
// +-------------------------+ (Optional)
// | .debug_info | (Optional)
// +-------------------------+ (Optional)
// | .debug_abbrev | (Optional)
// +-------------------------+ (Optional)
- // | .eh_frame | (Optional)
+ // | .debug_str | (Optional)
// +-------------------------+ (Optional)
// | .debug_line | (Optional)
// +-------------------------+ (Optional)
- // | .debug_str | (Optional)
- // +-------------------------+ (Optional)
// | Elf_Shdr NULL |
// | Elf_Shdr .dynsym |
// | Elf_Shdr .dynstr |
@@ -673,11 +677,12 @@
// | Elf_Shdr .bss | (Optional)
// | Elf_Shdr .dynamic |
// | Elf_Shdr .shstrtab |
+ // | Elf_Shdr .eh_frame | (Optional)
+ // | Elf_Shdr .eh_frame_hdr | (Optional)
// | Elf_Shdr .debug_info | (Optional)
// | Elf_Shdr .debug_abbrev | (Optional)
- // | Elf_Shdr .eh_frame | (Optional)
- // | Elf_Shdr .debug_line | (Optional)
// | Elf_Shdr .debug_str | (Optional)
+ // | Elf_Shdr .debug_line | (Optional)
// +-------------------------+
if (fatal_error_) {
@@ -718,6 +723,9 @@
program_headers_[PH_DYNAMIC].p_type = PT_DYNAMIC;
program_headers_[PH_DYNAMIC].p_flags = PF_R | PF_W;
+ program_headers_[PH_EH_FRAME_HDR].p_type = PT_NULL;
+ program_headers_[PH_EH_FRAME_HDR].p_flags = PF_R;
+
// Get the dynstr string.
dynstr_ = dynsym_builder_.GenerateStrtab();
@@ -828,10 +836,37 @@
hash_builder_.GetSection()->sh_size = hash_.size() * sizeof(Elf_Word);
hash_builder_.GetSection()->sh_link = hash_builder_.GetLink();
+ // Get the layout of the extra sections with SHF_ALLOC flag.
+ // This will deal with .eh_frame and .eh_frame_hdr.
+ // .eh_frame contains relative pointers to .text which we
+ // want to fixup between the calls to Init() and Write().
+ // Therefore we handle those sections here as opposed to Write().
+ // It also has the nice side effect of including .eh_frame
+ // with the rest of LOAD_R segment. It must come before .rodata
+ // because .rodata and .text must be next to each other.
+ Elf_Shdr* prev = hash_builder_.GetSection();
+ for (auto* it : other_builders_) {
+ if ((it->GetSection()->sh_flags & SHF_ALLOC) != 0) {
+ it->GetSection()->sh_offset = NextOffset<Elf_Word, Elf_Shdr>(*it->GetSection(), *prev);
+ it->GetSection()->sh_addr = it->GetSection()->sh_offset;
+ it->GetSection()->sh_size = it->GetBuffer()->size();
+ it->GetSection()->sh_link = it->GetLink();
+ prev = it->GetSection();
+ }
+ }
+ // If the sections exist, check that they have been handled.
+ const auto* eh_frame = FindRawSection(".eh_frame");
+ if (eh_frame != nullptr) {
+ DCHECK_NE(eh_frame->GetSection()->sh_offset, 0u);
+ }
+ const auto* eh_frame_hdr = FindRawSection(".eh_frame_hdr");
+ if (eh_frame_hdr != nullptr) {
+ DCHECK_NE(eh_frame_hdr->GetSection()->sh_offset, 0u);
+ }
+
// Get the layout of the rodata section.
rodata_builder_.GetSection()->sh_offset =
- NextOffset<Elf_Word, Elf_Shdr>(*rodata_builder_.GetSection(),
- *hash_builder_.GetSection());
+ NextOffset<Elf_Word, Elf_Shdr>(*rodata_builder_.GetSection(), *prev);
rodata_builder_.GetSection()->sh_addr = rodata_builder_.GetSection()->sh_offset;
rodata_builder_.GetSection()->sh_size = rodata_builder_.GetSize();
rodata_builder_.GetSection()->sh_link = rodata_builder_.GetLink();
@@ -909,9 +944,7 @@
}
// Setup all the other sections.
- for (ElfRawSectionBuilder<Elf_Word, Elf_Sword, Elf_Shdr> *builder = other_builders_.data(),
- *end = builder + other_builders_.size();
- builder != end; ++builder) {
+ for (auto* builder : other_builders_) {
section_ptrs_.push_back(builder->GetSection());
AssignSectionStr(builder, &shstrtab_);
builder->SetSectionIndex(section_index_);
@@ -958,20 +991,22 @@
}
}
- // Get the layout of the extra sections. (This will deal with the debug
- // sections if they are there)
- for (auto it = other_builders_.begin(); it != other_builders_.end(); ++it) {
- it->GetSection()->sh_offset = NextOffset<Elf_Word, Elf_Shdr>(*it->GetSection(), *prev);
- it->GetSection()->sh_addr = 0;
- it->GetSection()->sh_size = it->GetBuffer()->size();
- it->GetSection()->sh_link = it->GetLink();
+ // Get the layout of the extra sections without SHF_ALLOC flag.
+ // (This will deal with the debug sections if they are there)
+ for (auto* it : other_builders_) {
+ if ((it->GetSection()->sh_flags & SHF_ALLOC) == 0) {
+ it->GetSection()->sh_offset = NextOffset<Elf_Word, Elf_Shdr>(*it->GetSection(), *prev);
+ it->GetSection()->sh_addr = 0;
+ it->GetSection()->sh_size = it->GetBuffer()->size();
+ it->GetSection()->sh_link = it->GetLink();
- // We postpone adding an ElfFilePiece to keep the order in "pieces."
+ // We postpone adding an ElfFilePiece to keep the order in "pieces."
- prev = it->GetSection();
- if (debug_logging_) {
- LOG(INFO) << it->GetName() << " off=" << it->GetSection()->sh_offset
- << " size=" << it->GetSection()->sh_size;
+ prev = it->GetSection();
+ if (debug_logging_) {
+ LOG(INFO) << it->GetName() << " off=" << it->GetSection()->sh_offset
+ << " size=" << it->GetSection()->sh_size;
+ }
}
}
@@ -1044,6 +1079,26 @@
program_headers_[PH_DYNAMIC].p_memsz = dynamic_builder_.GetSection()->sh_size;
program_headers_[PH_DYNAMIC].p_align = dynamic_builder_.GetSection()->sh_addralign;
+ const auto* eh_frame_hdr = FindRawSection(".eh_frame_hdr");
+ if (eh_frame_hdr != nullptr) {
+ const auto* eh_frame = FindRawSection(".eh_frame");
+ // Check layout:
+ // 1) eh_frame is before eh_frame_hdr.
+ // 2) There's no gap.
+ CHECK(eh_frame != nullptr);
+ CHECK_LE(eh_frame->GetSection()->sh_offset, eh_frame_hdr->GetSection()->sh_offset);
+ CHECK_EQ(eh_frame->GetSection()->sh_offset + eh_frame->GetSection()->sh_size,
+ eh_frame_hdr->GetSection()->sh_offset);
+
+ program_headers_[PH_EH_FRAME_HDR].p_type = PT_GNU_EH_FRAME;
+ program_headers_[PH_EH_FRAME_HDR].p_offset = eh_frame_hdr->GetSection()->sh_offset;
+ program_headers_[PH_EH_FRAME_HDR].p_vaddr = eh_frame_hdr->GetSection()->sh_addr;
+ program_headers_[PH_EH_FRAME_HDR].p_paddr = eh_frame_hdr->GetSection()->sh_addr;
+ program_headers_[PH_EH_FRAME_HDR].p_filesz = eh_frame_hdr->GetSection()->sh_size;
+ program_headers_[PH_EH_FRAME_HDR].p_memsz = eh_frame_hdr->GetSection()->sh_size;
+ program_headers_[PH_EH_FRAME_HDR].p_align = eh_frame_hdr->GetSection()->sh_addralign;
+ }
+
// Finish setup of the Ehdr values.
elf_header_.e_phoff = PHDR_OFFSET;
elf_header_.e_shoff = sections_offset;
@@ -1108,7 +1163,7 @@
}
// Postponed debug info.
- for (auto it = other_builders_.begin(); it != other_builders_.end(); ++it) {
+ for (auto* it : other_builders_) {
pieces.push_back(new ElfFileMemoryPiece<Elf_Word>(it->GetName(), it->GetSection()->sh_offset,
it->GetBuffer()->data(),
it->GetBuffer()->size()));
@@ -1125,12 +1180,21 @@
return true;
}
- // Adds the given raw section to the builder. This will copy it. The caller
- // is responsible for deallocating their copy.
- void RegisterRawSection(ElfRawSectionBuilder<Elf_Word, Elf_Sword, Elf_Shdr> bld) {
+ // Adds the given raw section to the builder. It does not take ownership.
+ void RegisterRawSection(ElfRawSectionBuilder<Elf_Word, Elf_Sword, Elf_Shdr>* bld) {
other_builders_.push_back(bld);
}
+ const ElfRawSectionBuilder<Elf_Word, Elf_Sword, Elf_Shdr>*
+ FindRawSection(const char* name) {
+ for (const auto* other_builder : other_builders_) {
+ if (other_builder->GetName() == name) {
+ return other_builder;
+ }
+ }
+ return nullptr;
+ }
+
private:
void SetISA(InstructionSet isa) {
switch (isa) {
@@ -1282,7 +1346,8 @@
PH_LOAD_RW_BSS = 3,
PH_LOAD_RW_DYNAMIC = 4,
PH_DYNAMIC = 5,
- PH_NUM = 6,
+ PH_EH_FRAME_HDR = 6,
+ PH_NUM = 7,
};
static const uint32_t PHDR_SIZE = sizeof(Elf_Phdr) * PH_NUM;
Elf_Phdr program_headers_[PH_NUM];
@@ -1306,7 +1371,7 @@
ElfSectionBuilder<Elf_Word, Elf_Sword, Elf_Shdr> hash_builder_;
ElfDynamicBuilder<Elf_Word, Elf_Sword, Elf_Dyn, Elf_Shdr> dynamic_builder_;
ElfSectionBuilder<Elf_Word, Elf_Sword, Elf_Shdr> shstrtab_builder_;
- std::vector<ElfRawSectionBuilder<Elf_Word, Elf_Sword, Elf_Shdr>> other_builders_;
+ std::vector<ElfRawSectionBuilder<Elf_Word, Elf_Sword, Elf_Shdr>*> other_builders_;
DISALLOW_COPY_AND_ASSIGN(ElfBuilder);
};
diff --git a/compiler/elf_writer_debug.cc b/compiler/elf_writer_debug.cc
index 39233ce..cf0adae 100644
--- a/compiler/elf_writer_debug.cc
+++ b/compiler/elf_writer_debug.cc
@@ -28,7 +28,9 @@
namespace art {
namespace dwarf {
-static void WriteEhFrameCIE(InstructionSet isa, std::vector<uint8_t>* eh_frame) {
+static void WriteEhFrameCIE(InstructionSet isa,
+ ExceptionHeaderValueApplication addr_type,
+ std::vector<uint8_t>* eh_frame) {
// Scratch registers should be marked as undefined. This tells the
// debugger that its value in the previous frame is not recoverable.
bool is64bit = Is64BitInstructionSet(isa);
@@ -53,8 +55,8 @@
opcodes.SameValue(Reg::ArmFp(reg));
}
}
- auto return_address_reg = Reg::ArmCore(14); // R14(LR).
- WriteEhFrameCIE(is64bit, return_address_reg, opcodes, eh_frame);
+ auto return_reg = Reg::ArmCore(14); // R14(LR).
+ WriteEhFrameCIE(is64bit, addr_type, return_reg, opcodes, eh_frame);
return;
}
case kArm64: {
@@ -76,8 +78,8 @@
opcodes.SameValue(Reg::Arm64Fp(reg));
}
}
- auto return_address_reg = Reg::Arm64Core(30); // R30(LR).
- WriteEhFrameCIE(is64bit, return_address_reg, opcodes, eh_frame);
+ auto return_reg = Reg::Arm64Core(30); // R30(LR).
+ WriteEhFrameCIE(is64bit, addr_type, return_reg, opcodes, eh_frame);
return;
}
case kMips:
@@ -92,8 +94,8 @@
opcodes.SameValue(Reg::MipsCore(reg));
}
}
- auto return_address_reg = Reg::MipsCore(31); // R31(RA).
- WriteEhFrameCIE(is64bit, return_address_reg, opcodes, eh_frame);
+ auto return_reg = Reg::MipsCore(31); // R31(RA).
+ WriteEhFrameCIE(is64bit, addr_type, return_reg, opcodes, eh_frame);
return;
}
case kX86: {
@@ -114,8 +116,8 @@
for (int reg = 0; reg < 8; reg++) {
opcodes.Undefined(Reg::X86Fp(reg));
}
- auto return_address_reg = Reg::X86Core(8); // R8(EIP).
- WriteEhFrameCIE(is64bit, return_address_reg, opcodes, eh_frame);
+ auto return_reg = Reg::X86Core(8); // R8(EIP).
+ WriteEhFrameCIE(is64bit, addr_type, return_reg, opcodes, eh_frame);
return;
}
case kX86_64: {
@@ -140,8 +142,8 @@
opcodes.SameValue(Reg::X86_64Fp(reg));
}
}
- auto return_address_reg = Reg::X86_64Core(16); // R16(RIP).
- WriteEhFrameCIE(is64bit, return_address_reg, opcodes, eh_frame);
+ auto return_reg = Reg::X86_64Core(16); // R16(RIP).
+ WriteEhFrameCIE(is64bit, addr_type, return_reg, opcodes, eh_frame);
return;
}
case kNone:
@@ -152,22 +154,37 @@
}
void WriteEhFrame(const CompilerDriver* compiler,
- OatWriter* oat_writer,
- uint32_t text_section_offset,
- std::vector<uint8_t>* eh_frame) {
+ const OatWriter* oat_writer,
+ ExceptionHeaderValueApplication address_type,
+ std::vector<uint8_t>* eh_frame,
+ std::vector<uintptr_t>* eh_frame_patches,
+ std::vector<uint8_t>* eh_frame_hdr) {
const auto& method_infos = oat_writer->GetMethodDebugInfo();
const InstructionSet isa = compiler->GetInstructionSet();
+
+ // Write .eh_frame section.
size_t cie_offset = eh_frame->size();
- auto* eh_frame_patches = oat_writer->GetAbsolutePatchLocationsFor(".eh_frame");
- WriteEhFrameCIE(isa, eh_frame);
+ WriteEhFrameCIE(isa, address_type, eh_frame);
for (const OatWriter::DebugInfo& mi : method_infos) {
const SwapVector<uint8_t>* opcodes = mi.compiled_method_->GetCFIInfo();
if (opcodes != nullptr) {
WriteEhFrameFDE(Is64BitInstructionSet(isa), cie_offset,
- text_section_offset + mi.low_pc_, mi.high_pc_ - mi.low_pc_,
+ mi.low_pc_, mi.high_pc_ - mi.low_pc_,
opcodes, eh_frame, eh_frame_patches);
}
}
+
+ // Write .eh_frame_hdr section.
+ Writer<> header(eh_frame_hdr);
+ header.PushUint8(1); // Version.
+ header.PushUint8(DW_EH_PE_pcrel | DW_EH_PE_sdata4); // Encoding of .eh_frame pointer.
+ header.PushUint8(DW_EH_PE_omit); // Encoding of binary search table size.
+ header.PushUint8(DW_EH_PE_omit); // Encoding of binary search table addresses.
+ // .eh_frame pointer - .eh_frame_hdr section is after .eh_frame section, and need to encode
+ // relative to this location as libunwind doesn't honor datarel for eh_frame_hdr correctly.
+ header.PushInt32(-static_cast<int32_t>(eh_frame->size() + 4U));
+ // Omit binary search table size (number of entries).
+ // Omit binary search table.
}
/*
@@ -175,17 +192,20 @@
* @param oat_writer The Oat file Writer.
* @param eh_frame Call Frame Information.
* @param debug_info Compilation unit information.
+ * @param debug_info_patches Address locations to be patched.
* @param debug_abbrev Abbreviations used to generate dbg_info.
* @param debug_str Debug strings.
* @param debug_line Line number table.
+ * @param debug_line_patches Address locations to be patched.
*/
void WriteDebugSections(const CompilerDriver* compiler,
- OatWriter* oat_writer,
- uint32_t text_section_offset,
+ const OatWriter* oat_writer,
std::vector<uint8_t>* debug_info,
+ std::vector<uintptr_t>* debug_info_patches,
std::vector<uint8_t>* debug_abbrev,
std::vector<uint8_t>* debug_str,
- std::vector<uint8_t>* debug_line) {
+ std::vector<uint8_t>* debug_line,
+ std::vector<uintptr_t>* debug_line_patches) {
const std::vector<OatWriter::DebugInfo>& method_infos = oat_writer->GetMethodDebugInfo();
const InstructionSet isa = compiler->GetInstructionSet();
@@ -229,8 +249,8 @@
info.StartTag(DW_TAG_compile_unit, DW_CHILDREN_yes);
info.WriteStrp(DW_AT_producer, "Android dex2oat", debug_str);
info.WriteData1(DW_AT_language, DW_LANG_Java);
- info.WriteAddr(DW_AT_low_pc, cunit_low_pc + text_section_offset);
- info.WriteAddr(DW_AT_high_pc, cunit_high_pc + text_section_offset);
+ info.WriteAddr(DW_AT_low_pc, cunit_low_pc);
+ info.WriteAddr(DW_AT_high_pc, cunit_high_pc);
info.WriteData4(DW_AT_stmt_list, debug_line->size());
for (auto method_info : compilation_unit) {
std::string method_name = PrettyMethod(method_info->dex_method_index_,
@@ -240,12 +260,11 @@
}
info.StartTag(DW_TAG_subprogram, DW_CHILDREN_no);
info.WriteStrp(DW_AT_name, method_name.data(), debug_str);
- info.WriteAddr(DW_AT_low_pc, method_info->low_pc_ + text_section_offset);
- info.WriteAddr(DW_AT_high_pc, method_info->high_pc_ + text_section_offset);
+ info.WriteAddr(DW_AT_low_pc, method_info->low_pc_);
+ info.WriteAddr(DW_AT_high_pc, method_info->high_pc_);
info.EndTag(); // DW_TAG_subprogram
}
info.EndTag(); // DW_TAG_compile_unit
- auto* debug_info_patches = oat_writer->GetAbsolutePatchLocationsFor(".debug_info");
WriteDebugInfoCU(debug_abbrev_offset, info, debug_info, debug_info_patches);
// Write .debug_line section.
@@ -272,7 +291,7 @@
break;
}
DebugLineOpCodeWriter<> opcodes(false /* 32bit */, code_factor_bits_);
- opcodes.SetAddress(text_section_offset + cunit_low_pc);
+ opcodes.SetAddress(cunit_low_pc);
if (dwarf_isa != -1) {
opcodes.SetISA(dwarf_isa);
}
@@ -343,7 +362,6 @@
// Generate mapping opcodes from PC to Java lines.
const DefaultSrcMap& dex2line_map = debug_info_callbacks.dex2line_;
- uint32_t low_pc = text_section_offset + mi->low_pc_;
if (file_index != 0 && !dex2line_map.empty()) {
bool first = true;
for (SrcMapElem pc2dex : mi->compiled_method_->GetSrcMappingTable()) {
@@ -359,24 +377,23 @@
int first_line = dex2line_map.front().to_;
// Prologue is not a sensible place for a breakpoint.
opcodes.NegateStmt();
- opcodes.AddRow(low_pc, first_line);
+ opcodes.AddRow(mi->low_pc_, first_line);
opcodes.NegateStmt();
opcodes.SetPrologueEnd();
}
- opcodes.AddRow(low_pc + pc, line);
+ opcodes.AddRow(mi->low_pc_ + pc, line);
} else if (line != opcodes.CurrentLine()) {
- opcodes.AddRow(low_pc + pc, line);
+ opcodes.AddRow(mi->low_pc_ + pc, line);
}
}
}
} else {
// line 0 - instruction cannot be attributed to any source line.
- opcodes.AddRow(low_pc, 0);
+ opcodes.AddRow(mi->low_pc_, 0);
}
}
- opcodes.AdvancePC(text_section_offset + cunit_high_pc);
+ opcodes.AdvancePC(cunit_high_pc);
opcodes.EndSequence();
- auto* debug_line_patches = oat_writer->GetAbsolutePatchLocationsFor(".debug_line");
WriteDebugLineTable(directories, files, opcodes, debug_line, debug_line_patches);
}
}
diff --git a/compiler/elf_writer_debug.h b/compiler/elf_writer_debug.h
index 2c03b98..5bf4841 100644
--- a/compiler/elf_writer_debug.h
+++ b/compiler/elf_writer_debug.h
@@ -19,23 +19,27 @@
#include <vector>
+#include "dwarf/dwarf_constants.h"
#include "oat_writer.h"
namespace art {
namespace dwarf {
void WriteEhFrame(const CompilerDriver* compiler,
- OatWriter* oat_writer,
- uint32_t text_section_offset,
- std::vector<uint8_t>* eh_frame);
+ const OatWriter* oat_writer,
+ ExceptionHeaderValueApplication address_type,
+ std::vector<uint8_t>* eh_frame,
+ std::vector<uintptr_t>* eh_frame_patches,
+ std::vector<uint8_t>* eh_frame_hdr);
void WriteDebugSections(const CompilerDriver* compiler,
- OatWriter* oat_writer,
- uint32_t text_section_offset,
+ const OatWriter* oat_writer,
std::vector<uint8_t>* debug_info,
+ std::vector<uintptr_t>* debug_info_patches,
std::vector<uint8_t>* debug_abbrev,
std::vector<uint8_t>* debug_str,
- std::vector<uint8_t>* debug_line);
+ std::vector<uint8_t>* debug_line,
+ std::vector<uintptr_t>* debug_line_patches);
} // namespace dwarf
} // namespace art
diff --git a/compiler/elf_writer_quick.cc b/compiler/elf_writer_quick.cc
index 429cd85..44c14a0 100644
--- a/compiler/elf_writer_quick.cc
+++ b/compiler/elf_writer_quick.cc
@@ -70,8 +70,7 @@
template <typename Elf_Word, typename Elf_Sword, typename Elf_Addr,
typename Elf_Dyn, typename Elf_Sym, typename Elf_Ehdr,
typename Elf_Phdr, typename Elf_Shdr>
-static void WriteDebugSymbols(const CompilerDriver* compiler_driver,
- ElfBuilder<Elf_Word, Elf_Sword, Elf_Addr, Elf_Dyn,
+static void WriteDebugSymbols(ElfBuilder<Elf_Word, Elf_Sword, Elf_Addr, Elf_Dyn,
Elf_Sym, Elf_Ehdr, Elf_Phdr, Elf_Shdr>* builder,
OatWriter* oat_writer);
@@ -109,6 +108,19 @@
buffer->push_back(0); // End of sections.
}
+template<typename AddressType, bool SubtractPatchLocation = false>
+static void PatchAddresses(const std::vector<uintptr_t>* patch_locations,
+ AddressType delta, std::vector<uint8_t>* buffer) {
+ // Addresses in .debug_* sections are unaligned.
+ typedef __attribute__((__aligned__(1))) AddressType UnalignedAddressType;
+ if (patch_locations != nullptr) {
+ for (uintptr_t patch_location : *patch_locations) {
+ *reinterpret_cast<UnalignedAddressType*>(buffer->data() + patch_location) +=
+ delta - (SubtractPatchLocation ? patch_location : 0);
+ }
+ }
+}
+
template <typename Elf_Word, typename Elf_Sword, typename Elf_Addr,
typename Elf_Dyn, typename Elf_Sym, typename Elf_Ehdr,
typename Elf_Phdr, typename Elf_Shdr>
@@ -141,33 +153,77 @@
compiler_driver_->GetCompilerOptions().GetIncludeDebugSymbols(),
debug));
+ InstructionSet isa = compiler_driver_->GetInstructionSet();
+ int alignment = GetInstructionSetPointerSize(isa);
+ typedef ElfRawSectionBuilder<Elf_Word, Elf_Sword, Elf_Shdr> RawSection;
+ RawSection eh_frame(".eh_frame", SHT_PROGBITS, SHF_ALLOC, nullptr, 0, alignment, 0);
+ RawSection eh_frame_hdr(".eh_frame_hdr", SHT_PROGBITS, SHF_ALLOC, nullptr, 0, 4, 0);
+ RawSection debug_info(".debug_info", SHT_PROGBITS, 0, nullptr, 0, 1, 0);
+ RawSection debug_abbrev(".debug_abbrev", SHT_PROGBITS, 0, nullptr, 0, 1, 0);
+ RawSection debug_str(".debug_str", SHT_PROGBITS, 0, nullptr, 0, 1, 0);
+ RawSection debug_line(".debug_line", SHT_PROGBITS, 0, nullptr, 0, 1, 0);
+ RawSection oat_patches(".oat_patches", SHT_OAT_PATCH, 0, NULL, 0, 1, 0);
+
+ // Do not add to .oat_patches since we will make the addresses relative.
+ std::vector<uintptr_t> eh_frame_patches;
+ if (compiler_driver_->GetCompilerOptions().GetIncludeCFI() &&
+ !oat_writer->GetMethodDebugInfo().empty()) {
+ dwarf::WriteEhFrame(compiler_driver_, oat_writer,
+ dwarf::DW_EH_PE_pcrel,
+ eh_frame.GetBuffer(), &eh_frame_patches,
+ eh_frame_hdr.GetBuffer());
+ builder->RegisterRawSection(&eh_frame);
+ builder->RegisterRawSection(&eh_frame_hdr);
+ }
+
+ // Must be done after .eh_frame is created since it is used in the Elf layout.
if (!builder->Init()) {
return false;
}
- if (compiler_driver_->GetCompilerOptions().GetIncludeCFI() &&
- !oat_writer->GetMethodDebugInfo().empty()) {
- ElfRawSectionBuilder<Elf_Word, Elf_Sword, Elf_Shdr> eh_frame(
- ".eh_frame", SHT_PROGBITS, SHF_ALLOC, nullptr, 0, 4, 0);
- dwarf::WriteEhFrame(compiler_driver_, oat_writer,
- builder->GetTextBuilder().GetSection()->sh_addr,
- eh_frame.GetBuffer());
- builder->RegisterRawSection(eh_frame);
- }
-
+ std::vector<uintptr_t>* debug_info_patches = nullptr;
+ std::vector<uintptr_t>* debug_line_patches = nullptr;
if (compiler_driver_->GetCompilerOptions().GetIncludeDebugSymbols() &&
!oat_writer->GetMethodDebugInfo().empty()) {
- WriteDebugSymbols(compiler_driver_, builder.get(), oat_writer);
+ // Add methods to .symtab.
+ WriteDebugSymbols(builder.get(), oat_writer);
+ // Generate DWARF .debug_* sections.
+ debug_info_patches = oat_writer->GetAbsolutePatchLocationsFor(".debug_info");
+ debug_line_patches = oat_writer->GetAbsolutePatchLocationsFor(".debug_line");
+ dwarf::WriteDebugSections(compiler_driver_, oat_writer,
+ debug_info.GetBuffer(), debug_info_patches,
+ debug_abbrev.GetBuffer(),
+ debug_str.GetBuffer(),
+ debug_line.GetBuffer(), debug_line_patches);
+ builder->RegisterRawSection(&debug_info);
+ builder->RegisterRawSection(&debug_abbrev);
+ builder->RegisterRawSection(&debug_str);
+ builder->RegisterRawSection(&debug_line);
}
if (compiler_driver_->GetCompilerOptions().GetIncludePatchInformation() ||
// ElfWriter::Fixup will be called regardless and it needs to be able
// to patch debug sections so we have to include patches for them.
compiler_driver_->GetCompilerOptions().GetIncludeDebugSymbols()) {
- ElfRawSectionBuilder<Elf_Word, Elf_Sword, Elf_Shdr> oat_patches(
- ".oat_patches", SHT_OAT_PATCH, 0, NULL, 0, 1, 0);
EncodeOatPatches(oat_writer->GetAbsolutePatchLocations(), oat_patches.GetBuffer());
- builder->RegisterRawSection(oat_patches);
+ builder->RegisterRawSection(&oat_patches);
+ }
+
+ // We know where .text and .eh_frame will be located, so patch the addresses.
+ Elf_Addr text_addr = builder->GetTextBuilder().GetSection()->sh_addr;
+ // TODO: Simplify once we use Elf64 - we can use Elf_Addr instead of branching.
+ if (Is64BitInstructionSet(compiler_driver_->GetInstructionSet())) {
+ // relative_address = (text_addr + address) - (eh_frame_addr + patch_location);
+ PatchAddresses<uint64_t, true>(&eh_frame_patches,
+ text_addr - eh_frame.GetSection()->sh_addr, eh_frame.GetBuffer());
+ PatchAddresses<uint64_t>(debug_info_patches, text_addr, debug_info.GetBuffer());
+ PatchAddresses<uint64_t>(debug_line_patches, text_addr, debug_line.GetBuffer());
+ } else {
+ // relative_address = (text_addr + address) - (eh_frame_addr + patch_location);
+ PatchAddresses<uint32_t, true>(&eh_frame_patches,
+ text_addr - eh_frame.GetSection()->sh_addr, eh_frame.GetBuffer());
+ PatchAddresses<uint32_t>(debug_info_patches, text_addr, debug_info.GetBuffer());
+ PatchAddresses<uint32_t>(debug_line_patches, text_addr, debug_line.GetBuffer());
}
return builder->Write();
@@ -178,8 +234,7 @@
typename Elf_Phdr, typename Elf_Shdr>
// Do not inline to avoid Clang stack frame problems. b/18738594
NO_INLINE
-static void WriteDebugSymbols(const CompilerDriver* compiler_driver,
- ElfBuilder<Elf_Word, Elf_Sword, Elf_Addr, Elf_Dyn,
+static void WriteDebugSymbols(ElfBuilder<Elf_Word, Elf_Sword, Elf_Addr, Elf_Dyn,
Elf_Sym, Elf_Ehdr, Elf_Phdr, Elf_Shdr>* builder,
OatWriter* oat_writer) {
const std::vector<OatWriter::DebugInfo>& method_info = oat_writer->GetMethodDebugInfo();
@@ -214,25 +269,6 @@
0, STB_LOCAL, STT_NOTYPE);
}
}
-
- typedef ElfRawSectionBuilder<Elf_Word, Elf_Sword, Elf_Shdr> Section;
- Section debug_info(".debug_info", SHT_PROGBITS, 0, nullptr, 0, 1, 0);
- Section debug_abbrev(".debug_abbrev", SHT_PROGBITS, 0, nullptr, 0, 1, 0);
- Section debug_str(".debug_str", SHT_PROGBITS, 0, nullptr, 0, 1, 0);
- Section debug_line(".debug_line", SHT_PROGBITS, 0, nullptr, 0, 1, 0);
-
- dwarf::WriteDebugSections(compiler_driver,
- oat_writer,
- builder->GetTextBuilder().GetSection()->sh_addr,
- debug_info.GetBuffer(),
- debug_abbrev.GetBuffer(),
- debug_str.GetBuffer(),
- debug_line.GetBuffer());
-
- builder->RegisterRawSection(debug_info);
- builder->RegisterRawSection(debug_abbrev);
- builder->RegisterRawSection(debug_str);
- builder->RegisterRawSection(debug_line);
}
// Explicit instantiations
diff --git a/compiler/jit/jit_compiler.cc b/compiler/jit/jit_compiler.cc
index 9ff7ab8..6a08548 100644
--- a/compiler/jit/jit_compiler.cc
+++ b/compiler/jit/jit_compiler.cc
@@ -94,7 +94,7 @@
compiler_driver_.reset(new CompilerDriver(
compiler_options_.get(), verification_results_.get(), method_inliner_map_.get(),
Compiler::kQuick, instruction_set, instruction_set_features_.get(), false,
- nullptr, nullptr, 1, false, true,
+ nullptr, nullptr, nullptr, 1, false, true,
std::string(), cumulative_logger_.get(), -1, std::string()));
// Disable dedupe so we can remove compiled methods.
compiler_driver_->SetDedupeEnabled(false);
diff --git a/compiler/linker/relative_patcher_test.h b/compiler/linker/relative_patcher_test.h
index 70630f3..1f7500a 100644
--- a/compiler/linker/relative_patcher_test.h
+++ b/compiler/linker/relative_patcher_test.h
@@ -45,7 +45,7 @@
inliner_map_(),
driver_(&compiler_options_, &verification_results_, &inliner_map_,
Compiler::kQuick, instruction_set, nullptr,
- false, nullptr, nullptr, 1u,
+ false, nullptr, nullptr, nullptr, 1u,
false, false, "", nullptr, -1, ""),
error_msg_(),
instruction_set_(instruction_set),
diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc
index 989b04f..925b507 100644
--- a/compiler/oat_test.cc
+++ b/compiler/oat_test.cc
@@ -93,8 +93,8 @@
verification_results_.get(),
method_inliner_map_.get(),
compiler_kind, insn_set,
- insn_features.get(), false, nullptr, nullptr, 2, true,
- true, "", timer_.get(), -1, ""));
+ insn_features.get(), false, nullptr, nullptr, nullptr,
+ 2, true, true, "", timer_.get(), -1, ""));
jobject class_loader = nullptr;
if (kCompile) {
TimingLogger timings2("OatTest::WriteRead", false, false);
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index d8d2ae3..b404f8d 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -1023,14 +1023,14 @@
switch (compare->InputAt(0)->GetType()) {
case Primitive::kPrimLong: {
locations->SetInAt(0, Location::RequiresRegister());
- locations->SetInAt(1, Location::RegisterOrInt32LongConstant(compare->InputAt(1)));
+ locations->SetInAt(1, Location::Any());
locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
break;
}
case Primitive::kPrimFloat:
case Primitive::kPrimDouble: {
locations->SetInAt(0, Location::RequiresFpuRegister());
- locations->SetInAt(1, Location::RequiresFpuRegister());
+ locations->SetInAt(1, Location::Any());
locations->SetOut(Location::RequiresRegister());
break;
}
@@ -1052,24 +1052,46 @@
CpuRegister left_reg = left.AsRegister<CpuRegister>();
if (right.IsConstant()) {
int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
- DCHECK(IsInt<32>(value));
- if (value == 0) {
- __ testq(left_reg, left_reg);
+ if (IsInt<32>(value)) {
+ if (value == 0) {
+ __ testq(left_reg, left_reg);
+ } else {
+ __ cmpq(left_reg, Immediate(static_cast<int32_t>(value)));
+ }
} else {
- __ cmpq(left_reg, Immediate(static_cast<int32_t>(value)));
+ // Value won't fit in an int.
+ __ cmpq(left_reg, codegen_->LiteralInt64Address(value));
}
+ } else if (right.IsDoubleStackSlot()) {
+ __ cmpq(left_reg, Address(CpuRegister(RSP), right.GetStackIndex()));
} else {
__ cmpq(left_reg, right.AsRegister<CpuRegister>());
}
break;
}
case Primitive::kPrimFloat: {
- __ ucomiss(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
+ XmmRegister left_reg = left.AsFpuRegister<XmmRegister>();
+ if (right.IsConstant()) {
+ float value = right.GetConstant()->AsFloatConstant()->GetValue();
+ __ ucomiss(left_reg, codegen_->LiteralFloatAddress(value));
+ } else if (right.IsStackSlot()) {
+ __ ucomiss(left_reg, Address(CpuRegister(RSP), right.GetStackIndex()));
+ } else {
+ __ ucomiss(left_reg, right.AsFpuRegister<XmmRegister>());
+ }
__ j(kUnordered, compare->IsGtBias() ? &greater : &less);
break;
}
case Primitive::kPrimDouble: {
- __ ucomisd(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
+ XmmRegister left_reg = left.AsFpuRegister<XmmRegister>();
+ if (right.IsConstant()) {
+ double value = right.GetConstant()->AsDoubleConstant()->GetValue();
+ __ ucomisd(left_reg, codegen_->LiteralDoubleAddress(value));
+ } else if (right.IsDoubleStackSlot()) {
+ __ ucomisd(left_reg, Address(CpuRegister(RSP), right.GetStackIndex()));
+ } else {
+ __ ucomisd(left_reg, right.AsFpuRegister<XmmRegister>());
+ }
__ j(kUnordered, compare->IsGtBias() ? &greater : &less);
break;
}
@@ -1178,8 +1200,7 @@
case Primitive::kPrimFloat:
case Primitive::kPrimDouble:
- locations->SetInAt(0,
- Location::FpuRegisterLocation(XMM0));
+ locations->SetInAt(0, Location::FpuRegisterLocation(XMM0));
break;
default:
@@ -1419,7 +1440,6 @@
case Primitive::kPrimDouble:
locations->SetInAt(0, Location::RequiresFpuRegister());
locations->SetOut(Location::SameAsFirstInput());
- locations->AddTemp(Location::RequiresRegister());
locations->AddTemp(Location::RequiresFpuRegister());
break;
@@ -1447,26 +1467,22 @@
case Primitive::kPrimFloat: {
DCHECK(in.Equals(out));
- CpuRegister constant = locations->GetTemp(0).AsRegister<CpuRegister>();
- XmmRegister mask = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
+ XmmRegister mask = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
// Implement float negation with an exclusive or with value
// 0x80000000 (mask for bit 31, representing the sign of a
// single-precision floating-point number).
- __ movq(constant, Immediate(INT64_C(0x80000000)));
- __ movd(mask, constant);
+ __ movss(mask, codegen_->LiteralInt32Address(0x80000000));
__ xorps(out.AsFpuRegister<XmmRegister>(), mask);
break;
}
case Primitive::kPrimDouble: {
DCHECK(in.Equals(out));
- CpuRegister constant = locations->GetTemp(0).AsRegister<CpuRegister>();
- XmmRegister mask = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
+ XmmRegister mask = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
// Implement double negation with an exclusive or with value
// 0x8000000000000000 (mask for bit 63, representing the sign of
// a double-precision floating-point number).
- __ movq(constant, Immediate(INT64_C(0x8000000000000000)));
- __ movd(mask, constant);
+ __ movsd(mask, codegen_->LiteralInt64Address(INT64_C(0x8000000000000000)));
__ xorpd(out.AsFpuRegister<XmmRegister>(), mask);
break;
}
@@ -1613,19 +1629,19 @@
case Primitive::kPrimInt:
case Primitive::kPrimChar:
// Processing a Dex `int-to-float' instruction.
- locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetInAt(0, Location::Any());
locations->SetOut(Location::RequiresFpuRegister());
break;
case Primitive::kPrimLong:
// Processing a Dex `long-to-float' instruction.
- locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetInAt(0, Location::Any());
locations->SetOut(Location::RequiresFpuRegister());
break;
case Primitive::kPrimDouble:
// Processing a Dex `double-to-float' instruction.
- locations->SetInAt(0, Location::RequiresFpuRegister());
+ locations->SetInAt(0, Location::Any());
locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
break;
@@ -1644,19 +1660,19 @@
case Primitive::kPrimInt:
case Primitive::kPrimChar:
// Processing a Dex `int-to-double' instruction.
- locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetInAt(0, Location::Any());
locations->SetOut(Location::RequiresFpuRegister());
break;
case Primitive::kPrimLong:
// Processing a Dex `long-to-double' instruction.
- locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetInAt(0, Location::Any());
locations->SetOut(Location::RequiresFpuRegister());
break;
case Primitive::kPrimFloat:
// Processing a Dex `float-to-double' instruction.
- locations->SetInAt(0, Location::RequiresFpuRegister());
+ locations->SetInAt(0, Location::Any());
locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
break;
@@ -1910,17 +1926,56 @@
case Primitive::kPrimInt:
case Primitive::kPrimChar:
// Processing a Dex `int-to-float' instruction.
- __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), false);
+ if (in.IsRegister()) {
+ __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), false);
+ } else if (in.IsConstant()) {
+ int32_t v = in.GetConstant()->AsIntConstant()->GetValue();
+ XmmRegister dest = out.AsFpuRegister<XmmRegister>();
+ if (v == 0) {
+ __ xorps(dest, dest);
+ } else {
+ __ movss(dest, codegen_->LiteralFloatAddress(static_cast<float>(v)));
+ }
+ } else {
+ __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(),
+ Address(CpuRegister(RSP), in.GetStackIndex()), false);
+ }
break;
case Primitive::kPrimLong:
// Processing a Dex `long-to-float' instruction.
- __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), true);
+ if (in.IsRegister()) {
+ __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), true);
+ } else if (in.IsConstant()) {
+ int64_t v = in.GetConstant()->AsLongConstant()->GetValue();
+ XmmRegister dest = out.AsFpuRegister<XmmRegister>();
+ if (v == 0) {
+ __ xorps(dest, dest);
+ } else {
+ __ movss(dest, codegen_->LiteralFloatAddress(static_cast<float>(v)));
+ }
+ } else {
+ __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(),
+ Address(CpuRegister(RSP), in.GetStackIndex()), true);
+ }
break;
case Primitive::kPrimDouble:
// Processing a Dex `double-to-float' instruction.
- __ cvtsd2ss(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
+ if (in.IsFpuRegister()) {
+ __ cvtsd2ss(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
+ } else if (in.IsConstant()) {
+ double v = in.GetConstant()->AsDoubleConstant()->GetValue();
+ XmmRegister dest = out.AsFpuRegister<XmmRegister>();
+ if (bit_cast<int64_t, double>(v) == 0) {
+ __ xorps(dest, dest);
+ } else {
+ __ movss(dest, codegen_->LiteralFloatAddress(static_cast<float>(v)));
+ }
+ } else {
+ __ cvtsd2ss(out.AsFpuRegister<XmmRegister>(),
+ Address(CpuRegister(RSP), in.GetStackIndex()));
+ }
break;
default:
@@ -1938,17 +1993,56 @@
case Primitive::kPrimInt:
case Primitive::kPrimChar:
// Processing a Dex `int-to-double' instruction.
- __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), false);
+ if (in.IsRegister()) {
+ __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), false);
+ } else if (in.IsConstant()) {
+ int32_t v = in.GetConstant()->AsIntConstant()->GetValue();
+ XmmRegister dest = out.AsFpuRegister<XmmRegister>();
+ if (v == 0) {
+ __ xorpd(dest, dest);
+ } else {
+ __ movsd(dest, codegen_->LiteralDoubleAddress(static_cast<double>(v)));
+ }
+ } else {
+ __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(),
+ Address(CpuRegister(RSP), in.GetStackIndex()), false);
+ }
break;
case Primitive::kPrimLong:
// Processing a Dex `long-to-double' instruction.
- __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), true);
+ if (in.IsRegister()) {
+ __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), true);
+ } else if (in.IsConstant()) {
+ int64_t v = in.GetConstant()->AsLongConstant()->GetValue();
+ XmmRegister dest = out.AsFpuRegister<XmmRegister>();
+ if (v == 0) {
+ __ xorpd(dest, dest);
+ } else {
+ __ movsd(dest, codegen_->LiteralDoubleAddress(static_cast<double>(v)));
+ }
+ } else {
+ __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(),
+ Address(CpuRegister(RSP), in.GetStackIndex()), true);
+ }
break;
case Primitive::kPrimFloat:
// Processing a Dex `float-to-double' instruction.
- __ cvtss2sd(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
+ if (in.IsFpuRegister()) {
+ __ cvtss2sd(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
+ } else if (in.IsConstant()) {
+ float v = in.GetConstant()->AsFloatConstant()->GetValue();
+ XmmRegister dest = out.AsFpuRegister<XmmRegister>();
+ if (bit_cast<int32_t, float>(v) == 0) {
+ __ xorpd(dest, dest);
+ } else {
+ __ movsd(dest, codegen_->LiteralDoubleAddress(static_cast<double>(v)));
+ }
+ } else {
+ __ cvtss2sd(out.AsFpuRegister<XmmRegister>(),
+ Address(CpuRegister(RSP), in.GetStackIndex()));
+ }
break;
default:
@@ -3128,7 +3222,7 @@
if (Primitive::IsFloatingPointType(instruction->InputAt(1)->GetType())) {
locations->SetInAt(1, Location::RequiresFpuRegister());
} else {
- locations->SetInAt(1, Location::RequiresRegister());
+ locations->SetInAt(1, Location::RegisterOrInt32LongConstant(instruction->InputAt(1)));
}
if (needs_write_barrier) {
// Temporary registers for the write barrier.
@@ -3155,24 +3249,46 @@
switch (field_type) {
case Primitive::kPrimBoolean:
case Primitive::kPrimByte: {
- __ movb(Address(base, offset), value.AsRegister<CpuRegister>());
+ if (value.IsConstant()) {
+ int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
+ __ movb(Address(base, offset), Immediate(v));
+ } else {
+ __ movb(Address(base, offset), value.AsRegister<CpuRegister>());
+ }
break;
}
case Primitive::kPrimShort:
case Primitive::kPrimChar: {
- __ movw(Address(base, offset), value.AsRegister<CpuRegister>());
+ if (value.IsConstant()) {
+ int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
+ __ movw(Address(base, offset), Immediate(v));
+ } else {
+ __ movw(Address(base, offset), value.AsRegister<CpuRegister>());
+ }
break;
}
case Primitive::kPrimInt:
case Primitive::kPrimNot: {
- __ movl(Address(base, offset), value.AsRegister<CpuRegister>());
+ if (value.IsConstant()) {
+ int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
+ __ movw(Address(base, offset), Immediate(v));
+ } else {
+ __ movl(Address(base, offset), value.AsRegister<CpuRegister>());
+ }
break;
}
case Primitive::kPrimLong: {
- __ movq(Address(base, offset), value.AsRegister<CpuRegister>());
+ if (value.IsConstant()) {
+ int64_t v = value.GetConstant()->AsLongConstant()->GetValue();
+ DCHECK(IsInt<32>(v));
+ int32_t v_32 = v;
+ __ movq(Address(base, offset), Immediate(v_32));
+ } else {
+ __ movq(Address(base, offset), value.AsRegister<CpuRegister>());
+ }
break;
}
@@ -3291,8 +3407,7 @@
LocationSummary* locations =
new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
locations->SetInAt(0, Location::RequiresRegister());
- locations->SetInAt(
- 1, Location::RegisterOrConstant(instruction->InputAt(1)));
+ locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
if (Primitive::IsFloatingPointType(instruction->GetType())) {
locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
} else {
@@ -3431,7 +3546,7 @@
1, Location::RegisterOrConstant(instruction->InputAt(1)));
locations->SetInAt(2, Location::RequiresRegister());
if (value_type == Primitive::kPrimLong) {
- locations->SetInAt(2, Location::RequiresRegister());
+ locations->SetInAt(2, Location::RegisterOrInt32LongConstant(instruction->InputAt(2)));
} else if (value_type == Primitive::kPrimFloat || value_type == Primitive::kPrimDouble) {
locations->SetInAt(2, Location::RequiresFpuRegister());
} else {
@@ -3519,8 +3634,8 @@
__ movl(Address(obj, offset), value.AsRegister<CpuRegister>());
} else {
DCHECK(value.IsConstant()) << value;
- __ movl(Address(obj, offset),
- Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
+ int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
+ __ movl(Address(obj, offset), Immediate(v));
}
} else {
DCHECK(index.IsRegister()) << index;
@@ -3529,8 +3644,9 @@
value.AsRegister<CpuRegister>());
} else {
DCHECK(value.IsConstant()) << value;
+ int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
__ movl(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset),
- Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
+ Immediate(v));
}
}
codegen_->MaybeRecordImplicitNullCheck(instruction);
@@ -3554,12 +3670,25 @@
uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
if (index.IsConstant()) {
size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
- DCHECK(value.IsRegister());
- __ movq(Address(obj, offset), value.AsRegister<CpuRegister>());
+ if (value.IsRegister()) {
+ __ movq(Address(obj, offset), value.AsRegister<CpuRegister>());
+ } else {
+ int64_t v = value.GetConstant()->AsLongConstant()->GetValue();
+ DCHECK(IsInt<32>(v));
+ int32_t v_32 = v;
+ __ movq(Address(obj, offset), Immediate(v_32));
+ }
} else {
- DCHECK(value.IsRegister());
- __ movq(Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset),
- value.AsRegister<CpuRegister>());
+ if (value.IsRegister()) {
+ __ movq(Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset),
+ value.AsRegister<CpuRegister>());
+ } else {
+ int64_t v = value.GetConstant()->AsLongConstant()->GetValue();
+ DCHECK(IsInt<32>(v));
+ int32_t v_32 = v;
+ __ movq(Address(obj, index.AsRegister<CpuRegister>(), TIMES_8, data_offset),
+ Immediate(v_32));
+ }
}
codegen_->MaybeRecordImplicitNullCheck(instruction);
break;
@@ -4145,13 +4274,7 @@
DCHECK(instruction->GetResultType() == Primitive::kPrimInt
|| instruction->GetResultType() == Primitive::kPrimLong);
locations->SetInAt(0, Location::RequiresRegister());
- if (instruction->GetType() == Primitive::kPrimInt) {
- locations->SetInAt(1, Location::Any());
- } else {
- // We can handle 32 bit constants.
- locations->SetInAt(1, Location::RequiresRegister());
- locations->SetInAt(1, Location::RegisterOrInt32LongConstant(instruction->InputAt(1)));
- }
+ locations->SetInAt(1, Location::Any());
locations->SetOut(Location::SameAsFirstInput());
}
@@ -4212,25 +4335,43 @@
if (second.IsConstant()) {
second_is_constant = true;
value = second.GetConstant()->AsLongConstant()->GetValue();
- DCHECK(IsInt<32>(value));
}
+ bool is_int32_value = IsInt<32>(value);
if (instruction->IsAnd()) {
if (second_is_constant) {
- __ andq(first_reg, Immediate(static_cast<int32_t>(value)));
+ if (is_int32_value) {
+ __ andq(first_reg, Immediate(static_cast<int32_t>(value)));
+ } else {
+ __ andq(first_reg, codegen_->LiteralInt64Address(value));
+ }
+ } else if (second.IsDoubleStackSlot()) {
+ __ andq(first_reg, Address(CpuRegister(RSP), second.GetStackIndex()));
} else {
__ andq(first_reg, second.AsRegister<CpuRegister>());
}
} else if (instruction->IsOr()) {
if (second_is_constant) {
- __ orq(first_reg, Immediate(static_cast<int32_t>(value)));
+ if (is_int32_value) {
+ __ orq(first_reg, Immediate(static_cast<int32_t>(value)));
+ } else {
+ __ orq(first_reg, codegen_->LiteralInt64Address(value));
+ }
+ } else if (second.IsDoubleStackSlot()) {
+ __ orq(first_reg, Address(CpuRegister(RSP), second.GetStackIndex()));
} else {
__ orq(first_reg, second.AsRegister<CpuRegister>());
}
} else {
DCHECK(instruction->IsXor());
if (second_is_constant) {
- __ xorq(first_reg, Immediate(static_cast<int32_t>(value)));
+ if (is_int32_value) {
+ __ xorq(first_reg, Immediate(static_cast<int32_t>(value)));
+ } else {
+ __ xorq(first_reg, codegen_->LiteralInt64Address(value));
+ }
+ } else if (second.IsDoubleStackSlot()) {
+ __ xorq(first_reg, Address(CpuRegister(RSP), second.GetStackIndex()));
} else {
__ xorq(first_reg, second.AsRegister<CpuRegister>());
}
diff --git a/compiler/optimizing/graph_checker.cc b/compiler/optimizing/graph_checker.cc
index e743d8e..8950635 100644
--- a/compiler/optimizing/graph_checker.cc
+++ b/compiler/optimizing/graph_checker.cc
@@ -88,23 +88,36 @@
// Visit this block's list of phis.
for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
+ HInstruction* current = it.Current();
// Ensure this block's list of phis contains only phis.
- if (!it.Current()->IsPhi()) {
+ if (!current->IsPhi()) {
AddError(StringPrintf("Block %d has a non-phi in its phi list.",
current_block_->GetBlockId()));
}
- it.Current()->Accept(this);
+ if (current->GetNext() == nullptr && current != block->GetLastPhi()) {
+ AddError(StringPrintf("The recorded last phi of block %d does not match "
+ "the actual last phi %d.",
+ current_block_->GetBlockId(),
+ current->GetId()));
+ }
+ current->Accept(this);
}
// Visit this block's list of instructions.
- for (HInstructionIterator it(block->GetInstructions()); !it.Done();
- it.Advance()) {
+ for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
+ HInstruction* current = it.Current();
// Ensure this block's list of instructions does not contains phis.
- if (it.Current()->IsPhi()) {
+ if (current->IsPhi()) {
AddError(StringPrintf("Block %d has a phi in its non-phi list.",
current_block_->GetBlockId()));
}
- it.Current()->Accept(this);
+ if (current->GetNext() == nullptr && current != block->GetLastInstruction()) {
+ AddError(StringPrintf("The recorded last instruction of block %d does not match "
+ "the actual last instruction %d.",
+ current_block_->GetBlockId(),
+ current->GetId()));
+ }
+ current->Accept(this);
}
}
diff --git a/compiler/optimizing/intrinsics_x86_64.cc b/compiler/optimizing/intrinsics_x86_64.cc
index c718ece..5d24d1f 100644
--- a/compiler/optimizing/intrinsics_x86_64.cc
+++ b/compiler/optimizing/intrinsics_x86_64.cc
@@ -704,7 +704,6 @@
locations->SetInAt(0, Location::RequiresFpuRegister());
locations->SetOut(Location::RequiresFpuRegister());
locations->AddTemp(Location::RequiresFpuRegister());
- locations->AddTemp(Location::RequiresFpuRegister());
return;
}
@@ -732,14 +731,12 @@
// Implement RoundFloat as t1 = floor(input + 0.5f); convert to int.
XmmRegister in = locations->InAt(0).AsFpuRegister<XmmRegister>();
CpuRegister out = locations->Out().AsRegister<CpuRegister>();
- XmmRegister maxInt = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
- XmmRegister inPlusPointFive = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
+ XmmRegister inPlusPointFive = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
Label done, nan;
X86_64Assembler* assembler = GetAssembler();
- // Generate 0.5 into inPlusPointFive.
- __ movl(out, Immediate(bit_cast<int32_t, float>(0.5f)));
- __ movd(inPlusPointFive, out, false);
+ // Load 0.5 into inPlusPointFive.
+ __ movss(inPlusPointFive, codegen_->LiteralFloatAddress(0.5f));
// Add in the input.
__ addss(inPlusPointFive, in);
@@ -747,12 +744,8 @@
// And truncate to an integer.
__ roundss(inPlusPointFive, inPlusPointFive, Immediate(1));
- __ movl(out, Immediate(kPrimIntMax));
- // maxInt = int-to-float(out)
- __ cvtsi2ss(maxInt, out);
-
// if inPlusPointFive >= maxInt goto done
- __ comiss(inPlusPointFive, maxInt);
+ __ comiss(inPlusPointFive, codegen_->LiteralFloatAddress(static_cast<float>(kPrimIntMax)));
__ j(kAboveEqual, &done);
// if input == NaN goto nan
@@ -782,14 +775,12 @@
// Implement RoundDouble as t1 = floor(input + 0.5); convert to long.
XmmRegister in = locations->InAt(0).AsFpuRegister<XmmRegister>();
CpuRegister out = locations->Out().AsRegister<CpuRegister>();
- XmmRegister maxLong = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
- XmmRegister inPlusPointFive = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
+ XmmRegister inPlusPointFive = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
Label done, nan;
X86_64Assembler* assembler = GetAssembler();
- // Generate 0.5 into inPlusPointFive.
- __ movq(out, Immediate(bit_cast<int64_t, double>(0.5)));
- __ movd(inPlusPointFive, out, true);
+ // Load 0.5 into inPlusPointFive.
+ __ movsd(inPlusPointFive, codegen_->LiteralDoubleAddress(0.5));
// Add in the input.
__ addsd(inPlusPointFive, in);
@@ -797,12 +788,8 @@
// And truncate to an integer.
__ roundsd(inPlusPointFive, inPlusPointFive, Immediate(1));
- __ movq(out, Immediate(kPrimLongMax));
- // maxLong = long-to-double(out)
- __ cvtsi2sd(maxLong, out, true);
-
// if inPlusPointFive >= maxLong goto done
- __ comisd(inPlusPointFive, maxLong);
+ __ comisd(inPlusPointFive, codegen_->LiteralDoubleAddress(static_cast<double>(kPrimLongMax)));
__ j(kAboveEqual, &done);
// if input == NaN goto nan
@@ -960,26 +947,48 @@
LocationSummary::kNoCall,
kIntrinsified);
locations->SetInAt(0, Location::RequiresRegister());
- locations->SetInAt(1, Location::RequiresRegister());
+ locations->SetInAt(1, Location::RegisterOrInt32LongConstant(invoke->InputAt(1)));
}
static void GenPoke(LocationSummary* locations, Primitive::Type size, X86_64Assembler* assembler) {
CpuRegister address = locations->InAt(0).AsRegister<CpuRegister>();
- CpuRegister value = locations->InAt(1).AsRegister<CpuRegister>();
+ Location value = locations->InAt(1);
// x86 allows unaligned access. We do not have to check the input or use specific instructions
// to avoid a SIGBUS.
switch (size) {
case Primitive::kPrimByte:
- __ movb(Address(address, 0), value);
+ if (value.IsConstant()) {
+ __ movb(Address(address, 0),
+ Immediate(CodeGenerator::GetInt32ValueOf(value.GetConstant())));
+ } else {
+ __ movb(Address(address, 0), value.AsRegister<CpuRegister>());
+ }
break;
case Primitive::kPrimShort:
- __ movw(Address(address, 0), value);
+ if (value.IsConstant()) {
+ __ movw(Address(address, 0),
+ Immediate(CodeGenerator::GetInt32ValueOf(value.GetConstant())));
+ } else {
+ __ movw(Address(address, 0), value.AsRegister<CpuRegister>());
+ }
break;
case Primitive::kPrimInt:
- __ movl(Address(address, 0), value);
+ if (value.IsConstant()) {
+ __ movl(Address(address, 0),
+ Immediate(CodeGenerator::GetInt32ValueOf(value.GetConstant())));
+ } else {
+ __ movl(Address(address, 0), value.AsRegister<CpuRegister>());
+ }
break;
case Primitive::kPrimLong:
- __ movq(Address(address, 0), value);
+ if (value.IsConstant()) {
+ int64_t v = value.GetConstant()->AsLongConstant()->GetValue();
+ DCHECK(IsInt<32>(v));
+ int32_t v_32 = v;
+ __ movq(Address(address, 0), Immediate(v_32));
+ } else {
+ __ movq(Address(address, 0), value.AsRegister<CpuRegister>());
+ }
break;
default:
LOG(FATAL) << "Type not recognized for poke: " << size;
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index 4b9d4fc..bef5896 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -416,26 +416,6 @@
DCHECK(!instruction->HasEnvironment());
}
-void HBasicBlock::InsertInstructionBefore(HInstruction* instruction, HInstruction* cursor) {
- DCHECK(!cursor->IsPhi());
- DCHECK(!instruction->IsPhi());
- DCHECK_EQ(instruction->GetId(), -1);
- DCHECK_NE(cursor->GetId(), -1);
- DCHECK_EQ(cursor->GetBlock(), this);
- DCHECK(!instruction->IsControlFlow());
- instruction->next_ = cursor;
- instruction->previous_ = cursor->previous_;
- cursor->previous_ = instruction;
- if (GetFirstInstruction() == cursor) {
- instructions_.first_instruction_ = instruction;
- } else {
- instruction->previous_->next_ = instruction;
- }
- instruction->SetBlock(this);
- instruction->SetId(GetGraph()->GetNextInstructionId());
- UpdateInputsUsers(instruction);
-}
-
void HBasicBlock::ReplaceAndRemoveInstructionWith(HInstruction* initial,
HInstruction* replacement) {
DCHECK(initial->GetBlock() == this);
@@ -463,23 +443,27 @@
Add(&phis_, this, phi);
}
+void HBasicBlock::InsertInstructionBefore(HInstruction* instruction, HInstruction* cursor) {
+ DCHECK(!cursor->IsPhi());
+ DCHECK(!instruction->IsPhi());
+ DCHECK_EQ(instruction->GetId(), -1);
+ DCHECK_NE(cursor->GetId(), -1);
+ DCHECK_EQ(cursor->GetBlock(), this);
+ DCHECK(!instruction->IsControlFlow());
+ instruction->SetBlock(this);
+ instruction->SetId(GetGraph()->GetNextInstructionId());
+ UpdateInputsUsers(instruction);
+ instructions_.InsertInstructionBefore(instruction, cursor);
+}
+
void HBasicBlock::InsertPhiAfter(HPhi* phi, HPhi* cursor) {
DCHECK_EQ(phi->GetId(), -1);
DCHECK_NE(cursor->GetId(), -1);
DCHECK_EQ(cursor->GetBlock(), this);
- if (cursor->next_ == nullptr) {
- cursor->next_ = phi;
- phi->previous_ = cursor;
- DCHECK(phi->next_ == nullptr);
- } else {
- phi->next_ = cursor->next_;
- phi->previous_ = cursor;
- cursor->next_ = phi;
- phi->next_->previous_ = phi;
- }
phi->SetBlock(this);
phi->SetId(GetGraph()->GetNextInstructionId());
UpdateInputsUsers(phi);
+ phis_.InsertInstructionAfter(phi, cursor);
}
static void Remove(HInstructionList* instruction_list,
@@ -546,6 +530,34 @@
}
}
+void HInstructionList::InsertInstructionBefore(HInstruction* instruction, HInstruction* cursor) {
+ DCHECK(Contains(cursor));
+ if (cursor == first_instruction_) {
+ cursor->previous_ = instruction;
+ instruction->next_ = cursor;
+ first_instruction_ = instruction;
+ } else {
+ instruction->previous_ = cursor->previous_;
+ instruction->next_ = cursor;
+ cursor->previous_ = instruction;
+ instruction->previous_->next_ = instruction;
+ }
+}
+
+void HInstructionList::InsertInstructionAfter(HInstruction* instruction, HInstruction* cursor) {
+ DCHECK(Contains(cursor));
+ if (cursor == last_instruction_) {
+ cursor->next_ = instruction;
+ instruction->previous_ = cursor;
+ last_instruction_ = instruction;
+ } else {
+ instruction->next_ = cursor->next_;
+ instruction->previous_ = cursor;
+ cursor->next_ = instruction;
+ instruction->next_->previous_ = instruction;
+ }
+}
+
void HInstructionList::RemoveInstruction(HInstruction* instruction) {
if (instruction->previous_ != nullptr) {
instruction->previous_->next_ = instruction->next_;
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 08fcdbb..1a24cb5 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -75,6 +75,10 @@
void AddInstruction(HInstruction* instruction);
void RemoveInstruction(HInstruction* instruction);
+ // Insert `instruction` before/after an existing instruction `cursor`.
+ void InsertInstructionBefore(HInstruction* instruction, HInstruction* cursor);
+ void InsertInstructionAfter(HInstruction* instruction, HInstruction* cursor);
+
// Return true if this list contains `instruction`.
bool Contains(HInstruction* instruction) const;
@@ -467,8 +471,9 @@
HInstruction* GetFirstInstruction() const { return instructions_.first_instruction_; }
HInstruction* GetLastInstruction() const { return instructions_.last_instruction_; }
const HInstructionList& GetInstructions() const { return instructions_; }
- const HInstructionList& GetPhis() const { return phis_; }
HInstruction* GetFirstPhi() const { return phis_.first_instruction_; }
+ HInstruction* GetLastPhi() const { return phis_.last_instruction_; }
+ const HInstructionList& GetPhis() const { return phis_; }
void AddSuccessor(HBasicBlock* block) {
successors_.Add(block);
diff --git a/compiler/utils/x86_64/assembler_x86_64.cc b/compiler/utils/x86_64/assembler_x86_64.cc
index 32204a9..1ff99df 100644
--- a/compiler/utils/x86_64/assembler_x86_64.cc
+++ b/compiler/utils/x86_64/assembler_x86_64.cc
@@ -128,6 +128,16 @@
}
+void X86_64Assembler::movq(const Address& dst, const Immediate& imm) {
+ CHECK(imm.is_int32());
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitRex64(dst);
+ EmitUint8(0xC7);
+ EmitOperand(0, dst);
+ EmitImmediate(imm);
+}
+
+
void X86_64Assembler::movq(CpuRegister dst, CpuRegister src) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
// 0x89 is movq r/m64 <- r64, with op1 in r/m and op2 in reg: so reverse EmitRex64
@@ -652,6 +662,21 @@
}
+void X86_64Assembler::cvtsi2ss(XmmRegister dst, const Address& src, bool is64bit) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xF3);
+ if (is64bit) {
+ // Emit a REX.W prefix if the operand size is 64 bits.
+ EmitRex64(dst, src);
+ } else {
+ EmitOptionalRex32(dst, src);
+ }
+ EmitUint8(0x0F);
+ EmitUint8(0x2A);
+ EmitOperand(dst.LowBits(), src);
+}
+
+
void X86_64Assembler::cvtsi2sd(XmmRegister dst, CpuRegister src) {
cvtsi2sd(dst, src, false);
}
@@ -672,6 +697,21 @@
}
+void X86_64Assembler::cvtsi2sd(XmmRegister dst, const Address& src, bool is64bit) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xF2);
+ if (is64bit) {
+ // Emit a REX.W prefix if the operand size is 64 bits.
+ EmitRex64(dst, src);
+ } else {
+ EmitOptionalRex32(dst, src);
+ }
+ EmitUint8(0x0F);
+ EmitUint8(0x2A);
+ EmitOperand(dst.LowBits(), src);
+}
+
+
void X86_64Assembler::cvtss2si(CpuRegister dst, XmmRegister src) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0xF3);
@@ -692,6 +732,16 @@
}
+void X86_64Assembler::cvtss2sd(XmmRegister dst, const Address& src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xF3);
+ EmitOptionalRex32(dst, src);
+ EmitUint8(0x0F);
+ EmitUint8(0x5A);
+ EmitOperand(dst.LowBits(), src);
+}
+
+
void X86_64Assembler::cvtsd2si(CpuRegister dst, XmmRegister src) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0xF2);
@@ -752,6 +802,16 @@
}
+void X86_64Assembler::cvtsd2ss(XmmRegister dst, const Address& src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xF2);
+ EmitOptionalRex32(dst, src);
+ EmitUint8(0x0F);
+ EmitUint8(0x5A);
+ EmitOperand(dst.LowBits(), src);
+}
+
+
void X86_64Assembler::cvtdq2pd(XmmRegister dst, XmmRegister src) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0xF3);
@@ -771,6 +831,15 @@
}
+void X86_64Assembler::comiss(XmmRegister a, const Address& b) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitOptionalRex32(a, b);
+ EmitUint8(0x0F);
+ EmitUint8(0x2F);
+ EmitOperand(a.LowBits(), b);
+}
+
+
void X86_64Assembler::comisd(XmmRegister a, XmmRegister b) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0x66);
@@ -780,6 +849,17 @@
EmitXmmRegisterOperand(a.LowBits(), b);
}
+
+void X86_64Assembler::comisd(XmmRegister a, const Address& b) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x66);
+ EmitOptionalRex32(a, b);
+ EmitUint8(0x0F);
+ EmitUint8(0x2F);
+ EmitOperand(a.LowBits(), b);
+}
+
+
void X86_64Assembler::ucomiss(XmmRegister a, XmmRegister b) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitOptionalRex32(a, b);
@@ -789,6 +869,15 @@
}
+void X86_64Assembler::ucomiss(XmmRegister a, const Address& b) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitOptionalRex32(a, b);
+ EmitUint8(0x0F);
+ EmitUint8(0x2E);
+ EmitOperand(a.LowBits(), b);
+}
+
+
void X86_64Assembler::ucomisd(XmmRegister a, XmmRegister b) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0x66);
@@ -799,6 +888,16 @@
}
+void X86_64Assembler::ucomisd(XmmRegister a, const Address& b) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x66);
+ EmitOptionalRex32(a, b);
+ EmitUint8(0x0F);
+ EmitUint8(0x2E);
+ EmitOperand(a.LowBits(), b);
+}
+
+
void X86_64Assembler::roundsd(XmmRegister dst, XmmRegister src, const Immediate& imm) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0x66);
@@ -1161,7 +1260,7 @@
void X86_64Assembler::cmpq(CpuRegister reg, const Address& address) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
- EmitRex64(reg);
+ EmitRex64(reg, address);
EmitUint8(0x3B);
EmitOperand(reg.LowBits(), address);
}
@@ -1288,6 +1387,14 @@
}
+void X86_64Assembler::andq(CpuRegister dst, const Address& src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitRex64(dst, src);
+ EmitUint8(0x23);
+ EmitOperand(dst.LowBits(), src);
+}
+
+
void X86_64Assembler::orl(CpuRegister dst, CpuRegister src) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitOptionalRex32(dst, src);
@@ -1327,6 +1434,14 @@
}
+void X86_64Assembler::orq(CpuRegister dst, const Address& src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitRex64(dst, src);
+ EmitUint8(0x0B);
+ EmitOperand(dst.LowBits(), src);
+}
+
+
void X86_64Assembler::xorl(CpuRegister dst, CpuRegister src) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitOptionalRex32(dst, src);
@@ -1365,6 +1480,14 @@
EmitComplex(6, Operand(dst), imm);
}
+void X86_64Assembler::xorq(CpuRegister dst, const Address& src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitRex64(dst, src);
+ EmitUint8(0x33);
+ EmitOperand(dst.LowBits(), src);
+}
+
+
#if 0
void X86_64Assembler::rex(bool force, bool w, Register* r, Register* x, Register* b) {
// REX.WRXB
@@ -2182,9 +2305,15 @@
if (dst.NeedsRex()) {
rex |= 0x44; // REX.0R00
}
- if (rex != 0) {
- EmitUint8(rex);
+ EmitUint8(rex);
+}
+
+void X86_64Assembler::EmitRex64(XmmRegister dst, const Operand& operand) {
+ uint8_t rex = 0x48 | operand.rex(); // REX.W000
+ if (dst.NeedsRex()) {
+ rex |= 0x44; // REX.0R00
}
+ EmitUint8(rex);
}
void X86_64Assembler::EmitOptionalByteRegNormalizingRex32(CpuRegister dst, CpuRegister src) {
diff --git a/compiler/utils/x86_64/assembler_x86_64.h b/compiler/utils/x86_64/assembler_x86_64.h
index 16ef70b..79ad8f5 100644
--- a/compiler/utils/x86_64/assembler_x86_64.h
+++ b/compiler/utils/x86_64/assembler_x86_64.h
@@ -328,6 +328,7 @@
void movq(CpuRegister dst, const Address& src);
void movl(CpuRegister dst, const Address& src);
void movq(const Address& dst, CpuRegister src);
+ void movq(const Address& dst, const Immediate& src);
void movl(const Address& dst, CpuRegister src);
void movl(const Address& dst, const Immediate& imm);
@@ -391,14 +392,18 @@
void cvtsi2ss(XmmRegister dst, CpuRegister src); // Note: this is the r/m32 version.
void cvtsi2ss(XmmRegister dst, CpuRegister src, bool is64bit);
+ void cvtsi2ss(XmmRegister dst, const Address& src, bool is64bit);
void cvtsi2sd(XmmRegister dst, CpuRegister src); // Note: this is the r/m32 version.
void cvtsi2sd(XmmRegister dst, CpuRegister src, bool is64bit);
+ void cvtsi2sd(XmmRegister dst, const Address& src, bool is64bit);
void cvtss2si(CpuRegister dst, XmmRegister src); // Note: this is the r32 version.
void cvtss2sd(XmmRegister dst, XmmRegister src);
+ void cvtss2sd(XmmRegister dst, const Address& src);
void cvtsd2si(CpuRegister dst, XmmRegister src); // Note: this is the r32 version.
void cvtsd2ss(XmmRegister dst, XmmRegister src);
+ void cvtsd2ss(XmmRegister dst, const Address& src);
void cvttss2si(CpuRegister dst, XmmRegister src); // Note: this is the r32 version.
void cvttss2si(CpuRegister dst, XmmRegister src, bool is64bit);
@@ -408,9 +413,13 @@
void cvtdq2pd(XmmRegister dst, XmmRegister src);
void comiss(XmmRegister a, XmmRegister b);
+ void comiss(XmmRegister a, const Address& b);
void comisd(XmmRegister a, XmmRegister b);
+ void comisd(XmmRegister a, const Address& b);
void ucomiss(XmmRegister a, XmmRegister b);
+ void ucomiss(XmmRegister a, const Address& b);
void ucomisd(XmmRegister a, XmmRegister b);
+ void ucomisd(XmmRegister a, const Address& b);
void roundsd(XmmRegister dst, XmmRegister src, const Immediate& imm);
void roundss(XmmRegister dst, XmmRegister src, const Immediate& imm);
@@ -487,18 +496,21 @@
void andl(CpuRegister reg, const Address& address);
void andq(CpuRegister dst, const Immediate& imm);
void andq(CpuRegister dst, CpuRegister src);
+ void andq(CpuRegister reg, const Address& address);
void orl(CpuRegister dst, const Immediate& imm);
void orl(CpuRegister dst, CpuRegister src);
void orl(CpuRegister reg, const Address& address);
void orq(CpuRegister dst, CpuRegister src);
void orq(CpuRegister dst, const Immediate& imm);
+ void orq(CpuRegister reg, const Address& address);
void xorl(CpuRegister dst, CpuRegister src);
void xorl(CpuRegister dst, const Immediate& imm);
void xorl(CpuRegister reg, const Address& address);
void xorq(CpuRegister dst, const Immediate& imm);
void xorq(CpuRegister dst, CpuRegister src);
+ void xorq(CpuRegister reg, const Address& address);
void addl(CpuRegister dst, CpuRegister src);
void addl(CpuRegister reg, const Immediate& imm);
@@ -789,6 +801,7 @@
void EmitRex64(const Operand& operand);
void EmitRex64(CpuRegister dst, CpuRegister src);
void EmitRex64(CpuRegister dst, const Operand& operand);
+ void EmitRex64(XmmRegister dst, const Operand& operand);
void EmitRex64(XmmRegister dst, CpuRegister src);
void EmitRex64(CpuRegister dst, XmmRegister src);
diff --git a/compiler/utils/x86_64/assembler_x86_64_test.cc b/compiler/utils/x86_64/assembler_x86_64_test.cc
index 5ca0373..454cb02 100644
--- a/compiler/utils/x86_64/assembler_x86_64_test.cc
+++ b/compiler/utils/x86_64/assembler_x86_64_test.cc
@@ -667,6 +667,107 @@
DriverStr(expected, "movw");
}
+TEST_F(AssemblerX86_64Test, MovqAddrImm) {
+ GetAssembler()->movq(x86_64::Address(x86_64::CpuRegister(x86_64::RAX), 0),
+ x86_64::Immediate(-5));
+ const char* expected = "movq $-5, 0(%RAX)\n";
+ DriverStr(expected, "movq");
+}
+
+TEST_F(AssemblerX86_64Test, Cvtsi2ssAddr) {
+ GetAssembler()->cvtsi2ss(x86_64::XmmRegister(x86_64::XMM0),
+ x86_64::Address(x86_64::CpuRegister(x86_64::RAX), 0),
+ false);
+ GetAssembler()->cvtsi2ss(x86_64::XmmRegister(x86_64::XMM0),
+ x86_64::Address(x86_64::CpuRegister(x86_64::RAX), 0),
+ true);
+ const char* expected = "cvtsi2ss 0(%RAX), %xmm0\n"
+ "cvtsi2ssq 0(%RAX), %xmm0\n";
+ DriverStr(expected, "cvtsi2ss");
+}
+
+TEST_F(AssemblerX86_64Test, Cvtsi2sdAddr) {
+ GetAssembler()->cvtsi2sd(x86_64::XmmRegister(x86_64::XMM0),
+ x86_64::Address(x86_64::CpuRegister(x86_64::RAX), 0),
+ false);
+ GetAssembler()->cvtsi2sd(x86_64::XmmRegister(x86_64::XMM0),
+ x86_64::Address(x86_64::CpuRegister(x86_64::RAX), 0),
+ true);
+ const char* expected = "cvtsi2sd 0(%RAX), %xmm0\n"
+ "cvtsi2sdq 0(%RAX), %xmm0\n";
+ DriverStr(expected, "cvtsi2sd");
+}
+
+TEST_F(AssemblerX86_64Test, CmpqAddr) {
+ GetAssembler()->cmpq(x86_64::CpuRegister(x86_64::R12),
+ x86_64::Address(x86_64::CpuRegister(x86_64::R9), 0));
+ const char* expected = "cmpq 0(%R9), %R12\n";
+ DriverStr(expected, "cmpq");
+}
+
+TEST_F(AssemblerX86_64Test, Cvtss2sdAddr) {
+ GetAssembler()->cvtss2sd(x86_64::XmmRegister(x86_64::XMM0),
+ x86_64::Address(x86_64::CpuRegister(x86_64::RAX), 0));
+ const char* expected = "cvtss2sd 0(%RAX), %xmm0\n";
+ DriverStr(expected, "cvtss2sd");
+}
+
+TEST_F(AssemblerX86_64Test, Cvtsd2ssAddr) {
+ GetAssembler()->cvtsd2ss(x86_64::XmmRegister(x86_64::XMM0),
+ x86_64::Address(x86_64::CpuRegister(x86_64::RAX), 0));
+ const char* expected = "cvtsd2ss 0(%RAX), %xmm0\n";
+ DriverStr(expected, "cvtsd2ss");
+}
+
+TEST_F(AssemblerX86_64Test, ComissAddr) {
+ GetAssembler()->comiss(x86_64::XmmRegister(x86_64::XMM14),
+ x86_64::Address(x86_64::CpuRegister(x86_64::RAX), 0));
+ const char* expected = "comiss 0(%RAX), %xmm14\n";
+ DriverStr(expected, "comiss");
+}
+
+TEST_F(AssemblerX86_64Test, ComisdAddr) {
+ GetAssembler()->comisd(x86_64::XmmRegister(x86_64::XMM0),
+ x86_64::Address(x86_64::CpuRegister(x86_64::R9), 0));
+ const char* expected = "comisd 0(%R9), %xmm0\n";
+ DriverStr(expected, "comisd");
+}
+
+TEST_F(AssemblerX86_64Test, UComissAddr) {
+ GetAssembler()->ucomiss(x86_64::XmmRegister(x86_64::XMM0),
+ x86_64::Address(x86_64::CpuRegister(x86_64::RAX), 0));
+ const char* expected = "ucomiss 0(%RAX), %xmm0\n";
+ DriverStr(expected, "ucomiss");
+}
+
+TEST_F(AssemblerX86_64Test, UComisdAddr) {
+ GetAssembler()->ucomisd(x86_64::XmmRegister(x86_64::XMM0),
+ x86_64::Address(x86_64::CpuRegister(x86_64::RAX), 0));
+ const char* expected = "ucomisd 0(%RAX), %xmm0\n";
+ DriverStr(expected, "ucomisd");
+}
+
+TEST_F(AssemblerX86_64Test, Andq) {
+ GetAssembler()->andq(x86_64::CpuRegister(x86_64::R9),
+ x86_64::Address(x86_64::CpuRegister(x86_64::RAX), 0));
+ const char* expected = "andq 0(%RAX), %r9\n";
+ DriverStr(expected, "andq");
+}
+
+TEST_F(AssemblerX86_64Test, Orq) {
+ GetAssembler()->orq(x86_64::CpuRegister(x86_64::R9),
+ x86_64::Address(x86_64::CpuRegister(x86_64::RAX), 0));
+ const char* expected = "orq 0(%RAX), %r9\n";
+ DriverStr(expected, "orq");
+}
+
+TEST_F(AssemblerX86_64Test, Xorq) {
+ GetAssembler()->xorq(x86_64::CpuRegister(x86_64::R9),
+ x86_64::Address(x86_64::CpuRegister(x86_64::RAX), 0));
+ const char* expected = "xorq 0(%RAX), %r9\n";
+ DriverStr(expected, "xorq");
+}
+
TEST_F(AssemblerX86_64Test, Movsxd) {
DriverStr(RepeatRr(&x86_64::X86_64Assembler::movsxd, "movsxd %{reg2}, %{reg1}"), "movsxd");
}
diff --git a/dalvikvm/dalvikvm.cc b/dalvikvm/dalvikvm.cc
index 7839aa8..fd03002 100644
--- a/dalvikvm/dalvikvm.cc
+++ b/dalvikvm/dalvikvm.cc
@@ -50,6 +50,7 @@
int modifiers = env->CallIntMethod(reflected.get(), mid);
static const int PUBLIC = 0x0001; // java.lang.reflect.Modifiers.PUBLIC
if ((modifiers & PUBLIC) == 0) {
+ fprintf(stderr, "Modifiers mismatch\n");
return false;
}
return true;
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 70b4213..9c01a0f 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -445,6 +445,8 @@
image_classes_filename_(nullptr),
compiled_classes_zip_filename_(nullptr),
compiled_classes_filename_(nullptr),
+ compiled_methods_zip_filename_(nullptr),
+ compiled_methods_filename_(nullptr),
image_(false),
is_host_(false),
dump_stats_(false),
@@ -564,6 +566,10 @@
compiled_classes_filename_ = option.substr(strlen("--compiled-classes=")).data();
} else if (option.starts_with("--compiled-classes-zip=")) {
compiled_classes_zip_filename_ = option.substr(strlen("--compiled-classes-zip=")).data();
+ } else if (option.starts_with("--compiled-methods=")) {
+ compiled_methods_filename_ = option.substr(strlen("--compiled-methods=")).data();
+ } else if (option.starts_with("--compiled-methods-zip=")) {
+ compiled_methods_zip_filename_ = option.substr(strlen("--compiled-methods-zip=")).data();
} else if (option.starts_with("--base=")) {
const char* image_base_str = option.substr(strlen("--base=")).data();
char* end;
@@ -1092,8 +1098,8 @@
std::string error_msg;
if (image_classes_zip_filename_ != nullptr) {
image_classes_.reset(ReadImageClassesFromZip(image_classes_zip_filename_,
- image_classes_filename_,
- &error_msg));
+ image_classes_filename_,
+ &error_msg));
} else {
image_classes_.reset(ReadImageClassesFromFile(image_classes_filename_));
}
@@ -1121,9 +1127,29 @@
<< compiled_classes_filename_ << "': " << error_msg;
return false;
}
- } else if (image_) {
+ } else {
compiled_classes_.reset(nullptr); // By default compile everything.
}
+ // If --compiled-methods was specified, read the methods to compile from the given file(s).
+ if (compiled_methods_filename_ != nullptr) {
+ std::string error_msg;
+ if (compiled_methods_zip_filename_ != nullptr) {
+ compiled_methods_.reset(ReadCommentedInputFromZip(compiled_methods_zip_filename_,
+ compiled_methods_filename_,
+ nullptr, // No post-processing.
+ &error_msg));
+ } else {
+ compiled_methods_.reset(ReadCommentedInputFromFile(compiled_methods_filename_,
+ nullptr)); // No post-processing.
+ }
+ if (compiled_methods_.get() == nullptr) {
+ LOG(ERROR) << "Failed to create list of compiled methods from '"
+ << compiled_methods_filename_ << "': " << error_msg;
+ return false;
+ }
+ } else {
+ compiled_methods_.reset(nullptr); // By default compile everything.
+ }
if (boot_image_option_.empty()) {
dex_files_ = Runtime::Current()->GetClassLinker()->GetBootClassPath();
@@ -1258,6 +1284,7 @@
image_,
image_classes_.release(),
compiled_classes_.release(),
+ nullptr,
thread_count_,
dump_stats_,
dump_passes_,
@@ -1618,59 +1645,86 @@
// Reads the class names (java.lang.Object) and returns a set of descriptors (Ljava/lang/Object;)
static std::unordered_set<std::string>* ReadImageClassesFromFile(
const char* image_classes_filename) {
- std::unique_ptr<std::ifstream> image_classes_file(new std::ifstream(image_classes_filename,
- std::ifstream::in));
- if (image_classes_file.get() == nullptr) {
- LOG(ERROR) << "Failed to open image classes file " << image_classes_filename;
- return nullptr;
- }
- std::unique_ptr<std::unordered_set<std::string>> result(ReadImageClasses(*image_classes_file));
- image_classes_file->close();
- return result.release();
- }
-
- static std::unordered_set<std::string>* ReadImageClasses(std::istream& image_classes_stream) {
- std::unique_ptr<std::unordered_set<std::string>> image_classes(
- new std::unordered_set<std::string>);
- while (image_classes_stream.good()) {
- std::string dot;
- std::getline(image_classes_stream, dot);
- if (StartsWith(dot, "#") || dot.empty()) {
- continue;
- }
- std::string descriptor(DotToDescriptor(dot.c_str()));
- image_classes->insert(descriptor);
- }
- return image_classes.release();
+ std::function<std::string(const char*)> process = DotToDescriptor;
+ return ReadCommentedInputFromFile(image_classes_filename, &process);
}
// Reads the class names (java.lang.Object) and returns a set of descriptors (Ljava/lang/Object;)
static std::unordered_set<std::string>* ReadImageClassesFromZip(
+ const char* zip_filename,
+ const char* image_classes_filename,
+ std::string* error_msg) {
+ std::function<std::string(const char*)> process = DotToDescriptor;
+ return ReadCommentedInputFromZip(zip_filename, image_classes_filename, &process, error_msg);
+ }
+
+ // Read lines from the given file, dropping comments and empty lines. Post-process each line with
+ // the given function.
+ static std::unordered_set<std::string>* ReadCommentedInputFromFile(
+ const char* input_filename, std::function<std::string(const char*)>* process) {
+ std::unique_ptr<std::ifstream> input_file(new std::ifstream(input_filename, std::ifstream::in));
+ if (input_file.get() == nullptr) {
+ LOG(ERROR) << "Failed to open input file " << input_filename;
+ return nullptr;
+ }
+ std::unique_ptr<std::unordered_set<std::string>> result(
+ ReadCommentedInputStream(*input_file, process));
+ input_file->close();
+ return result.release();
+ }
+
+ // Read lines from the given file from the given zip file, dropping comments and empty lines.
+ // Post-process each line with the given function.
+ static std::unordered_set<std::string>* ReadCommentedInputFromZip(
const char* zip_filename,
- const char* image_classes_filename,
+ const char* input_filename,
+ std::function<std::string(const char*)>* process,
std::string* error_msg) {
std::unique_ptr<ZipArchive> zip_archive(ZipArchive::Open(zip_filename, error_msg));
if (zip_archive.get() == nullptr) {
return nullptr;
}
- std::unique_ptr<ZipEntry> zip_entry(zip_archive->Find(image_classes_filename, error_msg));
+ std::unique_ptr<ZipEntry> zip_entry(zip_archive->Find(input_filename, error_msg));
if (zip_entry.get() == nullptr) {
- *error_msg = StringPrintf("Failed to find '%s' within '%s': %s", image_classes_filename,
+ *error_msg = StringPrintf("Failed to find '%s' within '%s': %s", input_filename,
zip_filename, error_msg->c_str());
return nullptr;
}
- std::unique_ptr<MemMap> image_classes_file(zip_entry->ExtractToMemMap(zip_filename,
- image_classes_filename,
- error_msg));
- if (image_classes_file.get() == nullptr) {
- *error_msg = StringPrintf("Failed to extract '%s' from '%s': %s", image_classes_filename,
+ std::unique_ptr<MemMap> input_file(zip_entry->ExtractToMemMap(zip_filename,
+ input_filename,
+ error_msg));
+ if (input_file.get() == nullptr) {
+ *error_msg = StringPrintf("Failed to extract '%s' from '%s': %s", input_filename,
zip_filename, error_msg->c_str());
return nullptr;
}
- const std::string image_classes_string(reinterpret_cast<char*>(image_classes_file->Begin()),
- image_classes_file->Size());
- std::istringstream image_classes_stream(image_classes_string);
- return ReadImageClasses(image_classes_stream);
+ const std::string input_string(reinterpret_cast<char*>(input_file->Begin()),
+ input_file->Size());
+ std::istringstream input_stream(input_string);
+ return ReadCommentedInputStream(input_stream, process);
+ }
+
+ // Read lines from the given stream, dropping comments and empty lines. Post-process each line
+ // with the given function.
+ static std::unordered_set<std::string>* ReadCommentedInputStream(
+ std::istream& in_stream,
+ std::function<std::string(const char*)>* process) {
+ std::unique_ptr<std::unordered_set<std::string>> image_classes(
+ new std::unordered_set<std::string>);
+ while (in_stream.good()) {
+ std::string dot;
+ std::getline(in_stream, dot);
+ if (StartsWith(dot, "#") || dot.empty()) {
+ continue;
+ }
+ if (process != nullptr) {
+ std::string descriptor((*process)(dot.c_str()));
+ image_classes->insert(descriptor);
+ } else {
+ image_classes->insert(dot);
+ }
+ }
+ return image_classes.release();
}
void LogCompletionTime() {
@@ -1724,8 +1778,11 @@
const char* image_classes_filename_;
const char* compiled_classes_zip_filename_;
const char* compiled_classes_filename_;
+ const char* compiled_methods_zip_filename_;
+ const char* compiled_methods_filename_;
std::unique_ptr<std::unordered_set<std::string>> image_classes_;
std::unique_ptr<std::unordered_set<std::string>> compiled_classes_;
+ std::unique_ptr<std::unordered_set<std::string>> compiled_methods_;
bool image_;
std::unique_ptr<ImageWriter> image_writer_;
bool is_host_;
diff --git a/runtime/Android.mk b/runtime/Android.mk
index d3488fc..86201ba 100644
--- a/runtime/Android.mk
+++ b/runtime/Android.mk
@@ -100,11 +100,13 @@
linear_alloc.cc \
mem_map.cc \
memory_region.cc \
+ mirror/abstract_method.cc \
mirror/art_method.cc \
mirror/array.cc \
mirror/class.cc \
mirror/dex_cache.cc \
mirror/field.cc \
+ mirror/method.cc \
mirror/object.cc \
mirror/reference.cc \
mirror/stack_trace_element.cc \
diff --git a/runtime/arch/x86/fault_handler_x86.cc b/runtime/arch/x86/fault_handler_x86.cc
index 27a4adf..8712506 100644
--- a/runtime/arch/x86/fault_handler_x86.cc
+++ b/runtime/arch/x86/fault_handler_x86.cc
@@ -191,6 +191,7 @@
break;
case 0x81: // group 1, word immediate.
+ case 0xc7: // mov
modrm = *pc++;
has_modrm = true;
immediate_size = operand_size_prefix ? 2 : 4;
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 4e59217..85b245f 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -59,6 +59,7 @@
#include "mirror/dex_cache-inl.h"
#include "mirror/field.h"
#include "mirror/iftable-inl.h"
+#include "mirror/method.h"
#include "mirror/object-inl.h"
#include "mirror/object_array-inl.h"
#include "mirror/proxy.h"
@@ -258,8 +259,8 @@
CHECK(!init_done_);
// java_lang_Class comes first, it's needed for AllocClass
- Thread* self = Thread::Current();
- gc::Heap* heap = Runtime::Current()->GetHeap();
+ Thread* const self = Thread::Current();
+ gc::Heap* const heap = Runtime::Current()->GetHeap();
// The GC can't handle an object with a null class since we can't get the size of this object.
heap->IncrementDisableMovingGC(self);
StackHandleScope<64> hs(self); // 64 is picked arbitrarily.
@@ -436,20 +437,19 @@
// Object, String and DexCache need to be rerun through FindSystemClass to finish init
mirror::Class::SetStatus(java_lang_Object, mirror::Class::kStatusNotReady, self);
- mirror::Class* Object_class = FindSystemClass(self, "Ljava/lang/Object;");
- CHECK_EQ(java_lang_Object.Get(), Object_class);
+ CHECK_EQ(java_lang_Object.Get(), FindSystemClass(self, "Ljava/lang/Object;"));
CHECK_EQ(java_lang_Object->GetObjectSize(), mirror::Object::InstanceSize());
mirror::Class::SetStatus(java_lang_String, mirror::Class::kStatusNotReady, self);
mirror::Class* String_class = FindSystemClass(self, "Ljava/lang/String;");
- std::ostringstream os1, os2;
- java_lang_String->DumpClass(os1, mirror::Class::kDumpClassFullDetail);
- String_class->DumpClass(os2, mirror::Class::kDumpClassFullDetail);
- CHECK_EQ(java_lang_String.Get(), String_class) << os1.str() << "\n\n" << os2.str();
+ if (java_lang_String.Get() != String_class) {
+ std::ostringstream os1, os2;
+ java_lang_String->DumpClass(os1, mirror::Class::kDumpClassFullDetail);
+ String_class->DumpClass(os2, mirror::Class::kDumpClassFullDetail);
+ LOG(FATAL) << os1.str() << "\n\n" << os2.str();
+ }
CHECK_EQ(java_lang_String->GetObjectSize(), mirror::String::InstanceSize());
mirror::Class::SetStatus(java_lang_DexCache, mirror::Class::kStatusNotReady, self);
- mirror::Class* DexCache_class = FindSystemClass(self, "Ljava/lang/DexCache;");
- CHECK_EQ(java_lang_String.Get(), String_class);
- CHECK_EQ(java_lang_DexCache.Get(), DexCache_class);
+ CHECK_EQ(java_lang_DexCache.Get(), FindSystemClass(self, "Ljava/lang/DexCache;"));
CHECK_EQ(java_lang_DexCache->GetObjectSize(), mirror::DexCache::InstanceSize());
// Setup the primitive array type classes - can't be done until Object has a vtable.
@@ -459,17 +459,14 @@
SetClassRoot(kByteArrayClass, FindSystemClass(self, "[B"));
mirror::ByteArray::SetArrayClass(GetClassRoot(kByteArrayClass));
- mirror::Class* found_char_array_class = FindSystemClass(self, "[C");
- CHECK_EQ(char_array_class.Get(), found_char_array_class);
+ CHECK_EQ(char_array_class.Get(), FindSystemClass(self, "[C"));
SetClassRoot(kShortArrayClass, FindSystemClass(self, "[S"));
mirror::ShortArray::SetArrayClass(GetClassRoot(kShortArrayClass));
- mirror::Class* found_int_array_class = FindSystemClass(self, "[I");
- CHECK_EQ(int_array_class.Get(), found_int_array_class);
+ CHECK_EQ(int_array_class.Get(), FindSystemClass(self, "[I"));
- mirror::Class* found_long_array_class = FindSystemClass(self, "[J");
- CHECK_EQ(long_array_class.Get(), found_long_array_class);
+ CHECK_EQ(long_array_class.Get(), FindSystemClass(self, "[J"));
SetClassRoot(kFloatArrayClass, FindSystemClass(self, "[F"));
mirror::FloatArray::SetArrayClass(GetClassRoot(kFloatArrayClass));
@@ -477,97 +474,101 @@
SetClassRoot(kDoubleArrayClass, FindSystemClass(self, "[D"));
mirror::DoubleArray::SetArrayClass(GetClassRoot(kDoubleArrayClass));
- mirror::Class* found_class_array_class = FindSystemClass(self, "[Ljava/lang/Class;");
- CHECK_EQ(class_array_class.Get(), found_class_array_class);
+ CHECK_EQ(class_array_class.Get(), FindSystemClass(self, "[Ljava/lang/Class;"));
- mirror::Class* found_object_array_class = FindSystemClass(self, "[Ljava/lang/Object;");
- CHECK_EQ(object_array_class.Get(), found_object_array_class);
+ CHECK_EQ(object_array_class.Get(), FindSystemClass(self, "[Ljava/lang/Object;"));
// Setup the single, global copy of "iftable".
- mirror::Class* java_lang_Cloneable = FindSystemClass(self, "Ljava/lang/Cloneable;");
- CHECK(java_lang_Cloneable != nullptr);
- mirror::Class* java_io_Serializable = FindSystemClass(self, "Ljava/io/Serializable;");
- CHECK(java_io_Serializable != nullptr);
+ auto java_lang_Cloneable = hs.NewHandle(FindSystemClass(self, "Ljava/lang/Cloneable;"));
+ CHECK(java_lang_Cloneable.Get() != nullptr);
+ auto java_io_Serializable = hs.NewHandle(FindSystemClass(self, "Ljava/io/Serializable;"));
+ CHECK(java_io_Serializable.Get() != nullptr);
// We assume that Cloneable/Serializable don't have superinterfaces -- normally we'd have to
// crawl up and explicitly list all of the supers as well.
- {
- mirror::IfTable* array_iftable = array_iftable_.Read();
- array_iftable->SetInterface(0, java_lang_Cloneable);
- array_iftable->SetInterface(1, java_io_Serializable);
- }
+ array_iftable_.Read()->SetInterface(0, java_lang_Cloneable.Get());
+ array_iftable_.Read()->SetInterface(1, java_io_Serializable.Get());
- // Sanity check Class[] and Object[]'s interfaces.
- CHECK_EQ(java_lang_Cloneable, mirror::Class::GetDirectInterface(self, class_array_class, 0));
- CHECK_EQ(java_io_Serializable, mirror::Class::GetDirectInterface(self, class_array_class, 1));
- CHECK_EQ(java_lang_Cloneable, mirror::Class::GetDirectInterface(self, object_array_class, 0));
- CHECK_EQ(java_io_Serializable, mirror::Class::GetDirectInterface(self, object_array_class, 1));
+ // Sanity check Class[] and Object[]'s interfaces. GetDirectInterface may cause thread
+ // suspension.
+ CHECK_EQ(java_lang_Cloneable.Get(),
+ mirror::Class::GetDirectInterface(self, class_array_class, 0));
+ CHECK_EQ(java_io_Serializable.Get(),
+ mirror::Class::GetDirectInterface(self, class_array_class, 1));
+ CHECK_EQ(java_lang_Cloneable.Get(),
+ mirror::Class::GetDirectInterface(self, object_array_class, 0));
+ CHECK_EQ(java_io_Serializable.Get(),
+ mirror::Class::GetDirectInterface(self, object_array_class, 1));
// Run Class, ArtField, and ArtMethod through FindSystemClass. This initializes their
// dex_cache_ fields and register them in class_table_.
- mirror::Class* Class_class = FindSystemClass(self, "Ljava/lang/Class;");
- CHECK_EQ(java_lang_Class.Get(), Class_class);
+ CHECK_EQ(java_lang_Class.Get(), FindSystemClass(self, "Ljava/lang/Class;"));
mirror::Class::SetStatus(java_lang_reflect_ArtMethod, mirror::Class::kStatusNotReady, self);
- mirror::Class* Art_method_class = FindSystemClass(self, "Ljava/lang/reflect/ArtMethod;");
- CHECK_EQ(java_lang_reflect_ArtMethod.Get(), Art_method_class);
-
- mirror::Class* String_array_class =
- FindSystemClass(self, GetClassRootDescriptor(kJavaLangStringArrayClass));
- CHECK_EQ(object_array_string.Get(), String_array_class);
-
- mirror::Class* Art_method_array_class =
- FindSystemClass(self, GetClassRootDescriptor(kJavaLangReflectArtMethodArrayClass));
- CHECK_EQ(object_array_art_method.Get(), Art_method_array_class);
+ CHECK_EQ(java_lang_reflect_ArtMethod.Get(),
+ FindSystemClass(self, "Ljava/lang/reflect/ArtMethod;"));
+ CHECK_EQ(object_array_string.Get(),
+ FindSystemClass(self, GetClassRootDescriptor(kJavaLangStringArrayClass)));
+ CHECK_EQ(object_array_art_method.Get(),
+ FindSystemClass(self, GetClassRootDescriptor(kJavaLangReflectArtMethodArrayClass)));
// End of special init trickery, subsequent classes may be loaded via FindSystemClass.
// Create java.lang.reflect.Proxy root.
- mirror::Class* java_lang_reflect_Proxy = FindSystemClass(self, "Ljava/lang/reflect/Proxy;");
- SetClassRoot(kJavaLangReflectProxy, java_lang_reflect_Proxy);
+ SetClassRoot(kJavaLangReflectProxy, FindSystemClass(self, "Ljava/lang/reflect/Proxy;"));
// Create java.lang.reflect.Field.class root.
- mirror::Class* java_lang_reflect_Field = FindSystemClass(self, "Ljava/lang/reflect/Field;");
- CHECK(java_lang_reflect_Field != nullptr);
- SetClassRoot(kJavaLangReflectField, java_lang_reflect_Field);
- mirror::Field::SetClass(java_lang_reflect_Field);
+ auto* class_root = FindSystemClass(self, "Ljava/lang/reflect/Field;");
+ CHECK(class_root != nullptr);
+ SetClassRoot(kJavaLangReflectField, class_root);
+ mirror::Field::SetClass(class_root);
// Create java.lang.reflect.Field array root.
- mirror::Class* java_lang_reflect_Field_array =
- FindSystemClass(self, "[Ljava/lang/reflect/Field;");
- CHECK(java_lang_reflect_Field_array != nullptr);
- SetClassRoot(kJavaLangReflectFieldArrayClass, java_lang_reflect_Field_array);
- mirror::Field::SetArrayClass(java_lang_reflect_Field_array);
+ class_root = FindSystemClass(self, "[Ljava/lang/reflect/Field;");
+ CHECK(class_root != nullptr);
+ SetClassRoot(kJavaLangReflectFieldArrayClass, class_root);
+ mirror::Field::SetArrayClass(class_root);
+
+ // Create java.lang.reflect.Constructor.class root and array root.
+ class_root = FindSystemClass(self, "Ljava/lang/reflect/Constructor;");
+ CHECK(class_root != nullptr);
+ SetClassRoot(kJavaLangReflectConstructor, class_root);
+ mirror::Constructor::SetClass(class_root);
+ class_root = FindSystemClass(self, "[Ljava/lang/reflect/Constructor;");
+ CHECK(class_root != nullptr);
+ SetClassRoot(kJavaLangReflectConstructorArrayClass, class_root);
+ mirror::Constructor::SetArrayClass(class_root);
+
+ // Create java.lang.reflect.Method.class root and array root.
+ class_root = FindSystemClass(self, "Ljava/lang/reflect/Method;");
+ CHECK(class_root != nullptr);
+ SetClassRoot(kJavaLangReflectMethod, class_root);
+ mirror::Method::SetClass(class_root);
+ class_root = FindSystemClass(self, "[Ljava/lang/reflect/Method;");
+ CHECK(class_root != nullptr);
+ SetClassRoot(kJavaLangReflectMethodArrayClass, class_root);
+ mirror::Method::SetArrayClass(class_root);
// java.lang.ref classes need to be specially flagged, but otherwise are normal classes
// finish initializing Reference class
mirror::Class::SetStatus(java_lang_ref_Reference, mirror::Class::kStatusNotReady, self);
- mirror::Class* Reference_class = FindSystemClass(self, "Ljava/lang/ref/Reference;");
- CHECK_EQ(java_lang_ref_Reference.Get(), Reference_class);
+ CHECK_EQ(java_lang_ref_Reference.Get(), FindSystemClass(self, "Ljava/lang/ref/Reference;"));
CHECK_EQ(java_lang_ref_Reference->GetObjectSize(), mirror::Reference::InstanceSize());
CHECK_EQ(java_lang_ref_Reference->GetClassSize(), mirror::Reference::ClassSize());
- mirror::Class* java_lang_ref_FinalizerReference =
- FindSystemClass(self, "Ljava/lang/ref/FinalizerReference;");
- java_lang_ref_FinalizerReference->SetAccessFlags(
- java_lang_ref_FinalizerReference->GetAccessFlags() |
- kAccClassIsReference | kAccClassIsFinalizerReference);
- mirror::Class* java_lang_ref_PhantomReference =
- FindSystemClass(self, "Ljava/lang/ref/PhantomReference;");
- java_lang_ref_PhantomReference->SetAccessFlags(
- java_lang_ref_PhantomReference->GetAccessFlags() |
- kAccClassIsReference | kAccClassIsPhantomReference);
- mirror::Class* java_lang_ref_SoftReference =
- FindSystemClass(self, "Ljava/lang/ref/SoftReference;");
- java_lang_ref_SoftReference->SetAccessFlags(
- java_lang_ref_SoftReference->GetAccessFlags() | kAccClassIsReference);
- mirror::Class* java_lang_ref_WeakReference =
- FindSystemClass(self, "Ljava/lang/ref/WeakReference;");
- java_lang_ref_WeakReference->SetAccessFlags(
- java_lang_ref_WeakReference->GetAccessFlags() |
- kAccClassIsReference | kAccClassIsWeakReference);
+ class_root = FindSystemClass(self, "Ljava/lang/ref/FinalizerReference;");
+ class_root->SetAccessFlags(class_root->GetAccessFlags() |
+ kAccClassIsReference | kAccClassIsFinalizerReference);
+ class_root = FindSystemClass(self, "Ljava/lang/ref/PhantomReference;");
+ class_root->SetAccessFlags(class_root->GetAccessFlags() | kAccClassIsReference |
+ kAccClassIsPhantomReference);
+ class_root = FindSystemClass(self, "Ljava/lang/ref/SoftReference;");
+ class_root->SetAccessFlags(class_root->GetAccessFlags() | kAccClassIsReference);
+ class_root = FindSystemClass(self, "Ljava/lang/ref/WeakReference;");
+ class_root->SetAccessFlags(class_root->GetAccessFlags() | kAccClassIsReference |
+ kAccClassIsWeakReference);
// Setup the ClassLoader, verifying the object_size_.
- mirror::Class* java_lang_ClassLoader = FindSystemClass(self, "Ljava/lang/ClassLoader;");
- CHECK_EQ(java_lang_ClassLoader->GetObjectSize(), mirror::ClassLoader::InstanceSize());
- SetClassRoot(kJavaLangClassLoader, java_lang_ClassLoader);
+ class_root = FindSystemClass(self, "Ljava/lang/ClassLoader;");
+ CHECK_EQ(class_root->GetObjectSize(), mirror::ClassLoader::InstanceSize());
+ SetClassRoot(kJavaLangClassLoader, class_root);
// Set up java.lang.Throwable, java.lang.ClassNotFoundException, and
// java.lang.StackTraceElement as a convenience.
@@ -911,6 +912,10 @@
// String class root was set above
mirror::Field::SetClass(GetClassRoot(kJavaLangReflectField));
mirror::Field::SetArrayClass(GetClassRoot(kJavaLangReflectFieldArrayClass));
+ mirror::Constructor::SetClass(GetClassRoot(kJavaLangReflectConstructor));
+ mirror::Constructor::SetArrayClass(GetClassRoot(kJavaLangReflectConstructorArrayClass));
+ mirror::Method::SetClass(GetClassRoot(kJavaLangReflectMethod));
+ mirror::Method::SetArrayClass(GetClassRoot(kJavaLangReflectMethodArrayClass));
mirror::Reference::SetClass(GetClassRoot(kJavaLangRefReference));
mirror::BooleanArray::SetArrayClass(GetClassRoot(kBooleanArrayClass));
mirror::ByteArray::SetArrayClass(GetClassRoot(kByteArrayClass));
@@ -1096,22 +1101,26 @@
}
ClassLinker::~ClassLinker() {
- mirror::Class::ResetClass();
- mirror::String::ResetClass();
- mirror::Reference::ResetClass();
mirror::ArtMethod::ResetClass();
+ mirror::Class::ResetClass();
+ mirror::Constructor::ResetClass();
mirror::Field::ResetClass();
- mirror::Field::ResetArrayClass();
+ mirror::Method::ResetClass();
+ mirror::Reference::ResetClass();
+ mirror::StackTraceElement::ResetClass();
+ mirror::String::ResetClass();
+ mirror::Throwable::ResetClass();
mirror::BooleanArray::ResetArrayClass();
mirror::ByteArray::ResetArrayClass();
mirror::CharArray::ResetArrayClass();
+ mirror::Constructor::ResetArrayClass();
mirror::DoubleArray::ResetArrayClass();
+ mirror::Field::ResetArrayClass();
mirror::FloatArray::ResetArrayClass();
+ mirror::Method::ResetArrayClass();
mirror::IntArray::ResetArrayClass();
mirror::LongArray::ResetArrayClass();
mirror::ShortArray::ResetArrayClass();
- mirror::Throwable::ResetClass();
- mirror::StackTraceElement::ResetClass();
STLDeleteElements(&oat_files_);
}
@@ -2947,7 +2956,7 @@
jobjectArray interfaces, jobject loader,
jobjectArray methods, jobjectArray throws) {
Thread* self = soa.Self();
- StackHandleScope<8> hs(self);
+ StackHandleScope<9> hs(self);
MutableHandle<mirror::Class> klass(hs.NewHandle(
AllocClass(self, GetClassRoot(kJavaLangClass), sizeof(mirror::Class))));
if (klass.Get() == nullptr) {
@@ -3001,8 +3010,10 @@
}
// Create virtual method using specified prototypes.
- size_t num_virtual_methods =
- soa.Decode<mirror::ObjectArray<mirror::ArtMethod>*>(methods)->GetLength();
+ auto h_methods = hs.NewHandle(soa.Decode<mirror::ObjectArray<mirror::Method>*>(methods));
+ DCHECK_EQ(h_methods->GetClass(), mirror::Method::ArrayClass())
+ << PrettyClass(h_methods->GetClass());
+ const size_t num_virtual_methods = h_methods->GetLength();
{
mirror::ObjectArray<mirror::ArtMethod>* virtuals = AllocArtMethodArray(self,
num_virtual_methods);
@@ -3014,9 +3025,7 @@
}
for (size_t i = 0; i < num_virtual_methods; ++i) {
StackHandleScope<1> hs2(self);
- mirror::ObjectArray<mirror::ArtMethod>* decoded_methods =
- soa.Decode<mirror::ObjectArray<mirror::ArtMethod>*>(methods);
- Handle<mirror::ArtMethod> prototype(hs2.NewHandle(decoded_methods->Get(i)));
+ Handle<mirror::ArtMethod> prototype(hs2.NewHandle(h_methods->Get(i)->GetArtMethod()));
mirror::ArtMethod* clone = CreateProxyMethod(self, klass, prototype);
if (UNLIKELY(clone == nullptr)) {
CHECK(self->IsExceptionPending()); // OOME.
@@ -3066,9 +3075,7 @@
CheckProxyConstructor(klass->GetDirectMethod(0));
for (size_t i = 0; i < num_virtual_methods; ++i) {
StackHandleScope<2> hs2(self);
- mirror::ObjectArray<mirror::ArtMethod>* decoded_methods =
- soa.Decode<mirror::ObjectArray<mirror::ArtMethod>*>(methods);
- Handle<mirror::ArtMethod> prototype(hs2.NewHandle(decoded_methods->Get(i)));
+ Handle<mirror::ArtMethod> prototype(hs2.NewHandle(h_methods->Get(i)->GetArtMethod()));
Handle<mirror::ArtMethod> virtual_method(hs2.NewHandle(klass->GetVirtualMethod(i)));
CheckProxyMethod(virtual_method, prototype);
}
@@ -3104,23 +3111,22 @@
mirror::ArtMethod* proxy_method) {
DCHECK(proxy_class->IsProxyClass());
DCHECK(proxy_method->IsProxyMethod());
- // Locate the dex cache of the original interface/Object
- mirror::DexCache* dex_cache = nullptr;
{
ReaderMutexLock mu(Thread::Current(), dex_lock_);
- for (size_t i = 0; i != dex_caches_.size(); ++i) {
- mirror::DexCache* a_dex_cache = GetDexCache(i);
- if (proxy_method->HasSameDexCacheResolvedTypes(a_dex_cache->GetResolvedTypes())) {
- dex_cache = a_dex_cache;
- break;
+ // Locate the dex cache of the original interface/Object
+ for (const GcRoot<mirror::DexCache>& root : dex_caches_) {
+ auto* dex_cache = root.Read();
+ if (proxy_method->HasSameDexCacheResolvedTypes(dex_cache->GetResolvedTypes())) {
+ mirror::ArtMethod* resolved_method = dex_cache->GetResolvedMethod(
+ proxy_method->GetDexMethodIndex());
+ CHECK(resolved_method != nullptr);
+ return resolved_method;
}
}
}
- CHECK(dex_cache != nullptr);
- uint32_t method_idx = proxy_method->GetDexMethodIndex();
- mirror::ArtMethod* resolved_method = dex_cache->GetResolvedMethod(method_idx);
- CHECK(resolved_method != nullptr);
- return resolved_method;
+ LOG(FATAL) << "Didn't find dex cache for " << PrettyClass(proxy_class) << " "
+ << PrettyMethod(proxy_method);
+ UNREACHABLE();
}
@@ -3163,8 +3169,11 @@
Handle<mirror::ArtMethod> prototype) {
// Ensure prototype is in dex cache so that we can use the dex cache to look up the overridden
// prototype method
- prototype->GetDeclaringClass()->GetDexCache()->SetResolvedMethod(prototype->GetDexMethodIndex(),
- prototype.Get());
+ auto* dex_cache = prototype->GetDeclaringClass()->GetDexCache();
+ // Avoid dirtying the dex cache unless we need to.
+ if (dex_cache->GetResolvedMethod(prototype->GetDexMethodIndex()) != prototype.Get()) {
+ dex_cache->SetResolvedMethod(prototype->GetDexMethodIndex(), prototype.Get());
+ }
// We steal everything from the prototype (such as DexCache, invoke stub, etc.) then specialize
// as necessary
mirror::ArtMethod* method = down_cast<mirror::ArtMethod*>(prototype->Clone(self));
@@ -3198,6 +3207,7 @@
// interface prototype. The exception to this are Constructors and the Class of the Proxy itself.
CHECK(prototype->HasSameDexCacheResolvedMethods(method.Get()));
CHECK(prototype->HasSameDexCacheResolvedTypes(method.Get()));
+ CHECK_EQ(prototype->GetDeclaringClass()->GetDexCache(), method->GetDexCache());
CHECK_EQ(prototype->GetDexMethodIndex(), method->GetDexMethodIndex());
CHECK_STREQ(method->GetName(), prototype->GetName());
@@ -5210,11 +5220,15 @@
"Ljava/lang/DexCache;",
"Ljava/lang/ref/Reference;",
"Ljava/lang/reflect/ArtMethod;",
+ "Ljava/lang/reflect/Constructor;",
"Ljava/lang/reflect/Field;",
+ "Ljava/lang/reflect/Method;",
"Ljava/lang/reflect/Proxy;",
"[Ljava/lang/String;",
"[Ljava/lang/reflect/ArtMethod;",
+ "[Ljava/lang/reflect/Constructor;",
"[Ljava/lang/reflect/Field;",
+ "[Ljava/lang/reflect/Method;",
"Ljava/lang/ClassLoader;",
"Ljava/lang/Throwable;",
"Ljava/lang/ClassNotFoundException;",
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 68624b0..d7c625d 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -71,11 +71,15 @@
kJavaLangDexCache,
kJavaLangRefReference,
kJavaLangReflectArtMethod,
+ kJavaLangReflectConstructor,
kJavaLangReflectField,
+ kJavaLangReflectMethod,
kJavaLangReflectProxy,
kJavaLangStringArrayClass,
kJavaLangReflectArtMethodArrayClass,
+ kJavaLangReflectConstructorArrayClass,
kJavaLangReflectFieldArrayClass,
+ kJavaLangReflectMethodArrayClass,
kJavaLangClassLoader,
kJavaLangThrowable,
kJavaLangClassNotFoundException,
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index a31a785..7bee98f 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -25,6 +25,7 @@
#include "dex_file.h"
#include "entrypoints/entrypoint_utils-inl.h"
#include "gc/heap.h"
+#include "mirror/abstract_method.h"
#include "mirror/accessible_object.h"
#include "mirror/art_method-inl.h"
#include "mirror/class-inl.h"
@@ -463,6 +464,10 @@
return !error;
};
+ void addOffset(size_t offset, const char* name) {
+ offsets.push_back(CheckOffset(offset, name));
+ }
+
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(CheckOffsets);
};
@@ -472,142 +477,162 @@
struct ObjectOffsets : public CheckOffsets<mirror::Object> {
ObjectOffsets() : CheckOffsets<mirror::Object>(false, "Ljava/lang/Object;") {
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Object, klass_), "shadow$_klass_"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Object, monitor_), "shadow$_monitor_"));
+ addOffset(OFFSETOF_MEMBER(mirror::Object, klass_), "shadow$_klass_");
+ addOffset(OFFSETOF_MEMBER(mirror::Object, monitor_), "shadow$_monitor_");
#ifdef USE_BAKER_OR_BROOKS_READ_BARRIER
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Object, x_rb_ptr_), "shadow$_x_rb_ptr_"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Object, x_xpadding_), "shadow$_x_xpadding_"));
+ addOffset(OFFSETOF_MEMBER(mirror::Object, x_rb_ptr_), "shadow$_x_rb_ptr_");
+ addOffset(OFFSETOF_MEMBER(mirror::Object, x_xpadding_), "shadow$_x_xpadding_");
#endif
};
};
struct ArtMethodOffsets : public CheckOffsets<mirror::ArtMethod> {
ArtMethodOffsets() : CheckOffsets<mirror::ArtMethod>(false, "Ljava/lang/reflect/ArtMethod;") {
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, access_flags_), "accessFlags"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, declaring_class_), "declaringClass"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, dex_cache_resolved_methods_), "dexCacheResolvedMethods"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, dex_cache_resolved_types_), "dexCacheResolvedTypes"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, dex_code_item_offset_), "dexCodeItemOffset"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, dex_method_index_), "dexMethodIndex"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, method_index_), "methodIndex"));
+ addOffset(OFFSETOF_MEMBER(mirror::ArtMethod, access_flags_), "accessFlags");
+ addOffset(OFFSETOF_MEMBER(mirror::ArtMethod, declaring_class_), "declaringClass");
+ addOffset(OFFSETOF_MEMBER(mirror::ArtMethod, dex_cache_resolved_methods_),
+ "dexCacheResolvedMethods");
+ addOffset(OFFSETOF_MEMBER(mirror::ArtMethod, dex_cache_resolved_types_),
+ "dexCacheResolvedTypes");
+ addOffset(OFFSETOF_MEMBER(mirror::ArtMethod, dex_code_item_offset_), "dexCodeItemOffset");
+ addOffset(OFFSETOF_MEMBER(mirror::ArtMethod, dex_method_index_), "dexMethodIndex");
+ addOffset(OFFSETOF_MEMBER(mirror::ArtMethod, method_index_), "methodIndex");
};
};
struct ClassOffsets : public CheckOffsets<mirror::Class> {
ClassOffsets() : CheckOffsets<mirror::Class>(false, "Ljava/lang/Class;") {
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, access_flags_), "accessFlags"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, class_loader_), "classLoader"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, class_size_), "classSize"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, clinit_thread_id_), "clinitThreadId"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, component_type_), "componentType"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, dex_cache_), "dexCache"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, dex_cache_strings_), "dexCacheStrings"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, dex_class_def_idx_), "dexClassDefIndex"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, dex_type_idx_), "dexTypeIndex"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, direct_methods_), "directMethods"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, ifields_), "iFields"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, iftable_), "ifTable"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, name_), "name"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, num_instance_fields_), "numInstanceFields"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, num_reference_instance_fields_), "numReferenceInstanceFields"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, num_reference_static_fields_), "numReferenceStaticFields"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, num_static_fields_), "numStaticFields"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, object_size_), "objectSize"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, primitive_type_), "primitiveType"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, reference_instance_offsets_), "referenceInstanceOffsets"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, sfields_), "sFields"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, status_), "status"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, super_class_), "superClass"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, verify_error_class_), "verifyErrorClass"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, virtual_methods_), "virtualMethods"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, vtable_), "vtable"));
+ addOffset(OFFSETOF_MEMBER(mirror::Class, access_flags_), "accessFlags");
+ addOffset(OFFSETOF_MEMBER(mirror::Class, class_loader_), "classLoader");
+ addOffset(OFFSETOF_MEMBER(mirror::Class, class_size_), "classSize");
+ addOffset(OFFSETOF_MEMBER(mirror::Class, clinit_thread_id_), "clinitThreadId");
+ addOffset(OFFSETOF_MEMBER(mirror::Class, component_type_), "componentType");
+ addOffset(OFFSETOF_MEMBER(mirror::Class, dex_cache_), "dexCache");
+ addOffset(OFFSETOF_MEMBER(mirror::Class, dex_cache_strings_), "dexCacheStrings");
+ addOffset(OFFSETOF_MEMBER(mirror::Class, dex_class_def_idx_), "dexClassDefIndex");
+ addOffset(OFFSETOF_MEMBER(mirror::Class, dex_type_idx_), "dexTypeIndex");
+ addOffset(OFFSETOF_MEMBER(mirror::Class, direct_methods_), "directMethods");
+ addOffset(OFFSETOF_MEMBER(mirror::Class, ifields_), "iFields");
+ addOffset(OFFSETOF_MEMBER(mirror::Class, iftable_), "ifTable");
+ addOffset(OFFSETOF_MEMBER(mirror::Class, name_), "name");
+ addOffset(OFFSETOF_MEMBER(mirror::Class, num_instance_fields_), "numInstanceFields");
+ addOffset(OFFSETOF_MEMBER(mirror::Class, num_reference_instance_fields_),
+ "numReferenceInstanceFields");
+ addOffset(OFFSETOF_MEMBER(mirror::Class, num_reference_static_fields_),
+ "numReferenceStaticFields");
+ addOffset(OFFSETOF_MEMBER(mirror::Class, num_static_fields_), "numStaticFields");
+ addOffset(OFFSETOF_MEMBER(mirror::Class, object_size_), "objectSize");
+ addOffset(OFFSETOF_MEMBER(mirror::Class, primitive_type_), "primitiveType");
+ addOffset(OFFSETOF_MEMBER(mirror::Class, reference_instance_offsets_),
+ "referenceInstanceOffsets");
+ addOffset(OFFSETOF_MEMBER(mirror::Class, sfields_), "sFields");
+ addOffset(OFFSETOF_MEMBER(mirror::Class, status_), "status");
+ addOffset(OFFSETOF_MEMBER(mirror::Class, super_class_), "superClass");
+ addOffset(OFFSETOF_MEMBER(mirror::Class, verify_error_class_), "verifyErrorClass");
+ addOffset(OFFSETOF_MEMBER(mirror::Class, virtual_methods_), "virtualMethods");
+ addOffset(OFFSETOF_MEMBER(mirror::Class, vtable_), "vtable");
};
};
struct StringOffsets : public CheckOffsets<mirror::String> {
StringOffsets() : CheckOffsets<mirror::String>(false, "Ljava/lang/String;") {
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::String, count_), "count"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::String, hash_code_), "hashCode"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::String, offset_), "offset"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::String, array_), "value"));
+ addOffset(OFFSETOF_MEMBER(mirror::String, count_), "count");
+ addOffset(OFFSETOF_MEMBER(mirror::String, hash_code_), "hashCode");
+ addOffset(OFFSETOF_MEMBER(mirror::String, offset_), "offset");
+ addOffset(OFFSETOF_MEMBER(mirror::String, array_), "value");
};
};
struct ThrowableOffsets : public CheckOffsets<mirror::Throwable> {
ThrowableOffsets() : CheckOffsets<mirror::Throwable>(false, "Ljava/lang/Throwable;") {
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Throwable, cause_), "cause"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Throwable, detail_message_), "detailMessage"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Throwable, stack_state_), "stackState"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Throwable, stack_trace_), "stackTrace"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Throwable, suppressed_exceptions_), "suppressedExceptions"));
+ addOffset(OFFSETOF_MEMBER(mirror::Throwable, cause_), "cause");
+ addOffset(OFFSETOF_MEMBER(mirror::Throwable, detail_message_), "detailMessage");
+ addOffset(OFFSETOF_MEMBER(mirror::Throwable, stack_state_), "stackState");
+ addOffset(OFFSETOF_MEMBER(mirror::Throwable, stack_trace_), "stackTrace");
+ addOffset(OFFSETOF_MEMBER(mirror::Throwable, suppressed_exceptions_), "suppressedExceptions");
};
};
struct StackTraceElementOffsets : public CheckOffsets<mirror::StackTraceElement> {
- StackTraceElementOffsets() : CheckOffsets<mirror::StackTraceElement>(false, "Ljava/lang/StackTraceElement;") {
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::StackTraceElement, declaring_class_), "declaringClass"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::StackTraceElement, file_name_), "fileName"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::StackTraceElement, line_number_), "lineNumber"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::StackTraceElement, method_name_), "methodName"));
+ StackTraceElementOffsets() : CheckOffsets<mirror::StackTraceElement>(
+ false, "Ljava/lang/StackTraceElement;") {
+ addOffset(OFFSETOF_MEMBER(mirror::StackTraceElement, declaring_class_), "declaringClass");
+ addOffset(OFFSETOF_MEMBER(mirror::StackTraceElement, file_name_), "fileName");
+ addOffset(OFFSETOF_MEMBER(mirror::StackTraceElement, line_number_), "lineNumber");
+ addOffset(OFFSETOF_MEMBER(mirror::StackTraceElement, method_name_), "methodName");
};
};
struct ClassLoaderOffsets : public CheckOffsets<mirror::ClassLoader> {
ClassLoaderOffsets() : CheckOffsets<mirror::ClassLoader>(false, "Ljava/lang/ClassLoader;") {
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ClassLoader, packages_), "packages"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ClassLoader, parent_), "parent"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ClassLoader, proxyCache_), "proxyCache"));
+ addOffset(OFFSETOF_MEMBER(mirror::ClassLoader, packages_), "packages");
+ addOffset(OFFSETOF_MEMBER(mirror::ClassLoader, parent_), "parent");
+ addOffset(OFFSETOF_MEMBER(mirror::ClassLoader, proxyCache_), "proxyCache");
};
};
struct ProxyOffsets : public CheckOffsets<mirror::Proxy> {
ProxyOffsets() : CheckOffsets<mirror::Proxy>(false, "Ljava/lang/reflect/Proxy;") {
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Proxy, h_), "h"));
+ addOffset(OFFSETOF_MEMBER(mirror::Proxy, h_), "h");
};
};
struct DexCacheOffsets : public CheckOffsets<mirror::DexCache> {
DexCacheOffsets() : CheckOffsets<mirror::DexCache>(false, "Ljava/lang/DexCache;") {
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::DexCache, dex_), "dex"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::DexCache, dex_file_), "dexFile"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::DexCache, location_), "location"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::DexCache, resolved_fields_), "resolvedFields"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::DexCache, resolved_methods_), "resolvedMethods"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::DexCache, resolved_types_), "resolvedTypes"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::DexCache, strings_), "strings"));
+ addOffset(OFFSETOF_MEMBER(mirror::DexCache, dex_), "dex");
+ addOffset(OFFSETOF_MEMBER(mirror::DexCache, dex_file_), "dexFile");
+ addOffset(OFFSETOF_MEMBER(mirror::DexCache, location_), "location");
+ addOffset(OFFSETOF_MEMBER(mirror::DexCache, resolved_fields_), "resolvedFields");
+ addOffset(OFFSETOF_MEMBER(mirror::DexCache, resolved_methods_), "resolvedMethods");
+ addOffset(OFFSETOF_MEMBER(mirror::DexCache, resolved_types_), "resolvedTypes");
+ addOffset(OFFSETOF_MEMBER(mirror::DexCache, strings_), "strings");
};
};
struct ReferenceOffsets : public CheckOffsets<mirror::Reference> {
ReferenceOffsets() : CheckOffsets<mirror::Reference>(false, "Ljava/lang/ref/Reference;") {
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Reference, pending_next_), "pendingNext"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Reference, queue_), "queue"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Reference, queue_next_), "queueNext"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Reference, referent_), "referent"));
+ addOffset(OFFSETOF_MEMBER(mirror::Reference, pending_next_), "pendingNext");
+ addOffset(OFFSETOF_MEMBER(mirror::Reference, queue_), "queue");
+ addOffset(OFFSETOF_MEMBER(mirror::Reference, queue_next_), "queueNext");
+ addOffset(OFFSETOF_MEMBER(mirror::Reference, referent_), "referent");
};
};
struct FinalizerReferenceOffsets : public CheckOffsets<mirror::FinalizerReference> {
- FinalizerReferenceOffsets() : CheckOffsets<mirror::FinalizerReference>(false, "Ljava/lang/ref/FinalizerReference;") {
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::FinalizerReference, next_), "next"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::FinalizerReference, prev_), "prev"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::FinalizerReference, zombie_), "zombie"));
+ FinalizerReferenceOffsets() : CheckOffsets<mirror::FinalizerReference>(
+ false, "Ljava/lang/ref/FinalizerReference;") {
+ addOffset(OFFSETOF_MEMBER(mirror::FinalizerReference, next_), "next");
+ addOffset(OFFSETOF_MEMBER(mirror::FinalizerReference, prev_), "prev");
+ addOffset(OFFSETOF_MEMBER(mirror::FinalizerReference, zombie_), "zombie");
};
};
struct AccessibleObjectOffsets : public CheckOffsets<mirror::AccessibleObject> {
- AccessibleObjectOffsets() : CheckOffsets<mirror::AccessibleObject>(false, "Ljava/lang/reflect/AccessibleObject;") {
- offsets.push_back(CheckOffset(mirror::AccessibleObject::FlagOffset().Uint32Value(), "flag"));
+ AccessibleObjectOffsets() : CheckOffsets<mirror::AccessibleObject>(
+ false, "Ljava/lang/reflect/AccessibleObject;") {
+ addOffset(mirror::AccessibleObject::FlagOffset().Uint32Value(), "flag");
};
};
struct FieldOffsets : public CheckOffsets<mirror::Field> {
FieldOffsets() : CheckOffsets<mirror::Field>(false, "Ljava/lang/reflect/Field;") {
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Field, access_flags_), "accessFlags"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Field, declaring_class_), "declaringClass"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Field, dex_field_index_), "dexFieldIndex"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Field, offset_), "offset"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Field, type_), "type"));
+ addOffset(OFFSETOF_MEMBER(mirror::Field, access_flags_), "accessFlags");
+ addOffset(OFFSETOF_MEMBER(mirror::Field, declaring_class_), "declaringClass");
+ addOffset(OFFSETOF_MEMBER(mirror::Field, dex_field_index_), "dexFieldIndex");
+ addOffset(OFFSETOF_MEMBER(mirror::Field, offset_), "offset");
+ addOffset(OFFSETOF_MEMBER(mirror::Field, type_), "type");
+ };
+};
+
+struct AbstractMethodOffsets : public CheckOffsets<mirror::AbstractMethod> {
+ AbstractMethodOffsets() : CheckOffsets<mirror::AbstractMethod>(
+ false, "Ljava/lang/reflect/AbstractMethod;") {
+ addOffset(OFFSETOF_MEMBER(mirror::AbstractMethod, access_flags_), "accessFlags");
+ addOffset(OFFSETOF_MEMBER(mirror::AbstractMethod, art_method_), "artMethod");
+ addOffset(OFFSETOF_MEMBER(mirror::AbstractMethod, declaring_class_), "declaringClass");
+ addOffset(OFFSETOF_MEMBER(mirror::AbstractMethod, declaring_class_of_overridden_method_),
+ "declaringClassOfOverriddenMethod");
+ addOffset(OFFSETOF_MEMBER(mirror::AbstractMethod, dex_method_index_), "dexMethodIndex");
};
};
@@ -629,6 +654,7 @@
EXPECT_TRUE(FinalizerReferenceOffsets().Check());
EXPECT_TRUE(AccessibleObjectOffsets().Check());
EXPECT_TRUE(FieldOffsets().Check());
+ EXPECT_TRUE(AbstractMethodOffsets().Check());
}
TEST_F(ClassLinkerTest, FindClassNonexistent) {
diff --git a/runtime/elf_file.cc b/runtime/elf_file.cc
index f2b013f..37e391d 100644
--- a/runtime/elf_file.cc
+++ b/runtime/elf_file.cc
@@ -1606,9 +1606,6 @@
if (base_address_delta == 0) {
return true;
}
- if (!ApplyOatPatchesTo(".eh_frame", base_address_delta)) {
- return false;
- }
if (!ApplyOatPatchesTo(".debug_info", base_address_delta)) {
return false;
}
diff --git a/runtime/entrypoints/entrypoint_utils.cc b/runtime/entrypoints/entrypoint_utils.cc
index 1d8df68..768f505 100644
--- a/runtime/entrypoints/entrypoint_utils.cc
+++ b/runtime/entrypoints/entrypoint_utils.cc
@@ -23,6 +23,7 @@
#include "gc/accounting/card_table-inl.h"
#include "mirror/art_method-inl.h"
#include "mirror/class-inl.h"
+#include "mirror/method.h"
#include "mirror/object-inl.h"
#include "mirror/object_array-inl.h"
#include "reflection.h"
@@ -257,7 +258,7 @@
}
}
- // Call Proxy.invoke(Proxy proxy, ArtMethod method, Object[] args).
+ // Call Proxy.invoke(Proxy proxy, Method method, Object[] args).
jvalue invocation_args[3];
invocation_args[0].l = rcvr_jobj;
invocation_args[1].l = interface_method_jobj;
@@ -274,10 +275,9 @@
return zero;
} else {
StackHandleScope<1> hs(soa.Self());
- Handle<mirror::ArtMethod> h_interface_method(
- hs.NewHandle(soa.Decode<mirror::ArtMethod*>(interface_method_jobj)));
+ auto h_interface_method(hs.NewHandle(soa.Decode<mirror::Method*>(interface_method_jobj)));
// This can cause thread suspension.
- mirror::Class* result_type = h_interface_method->GetReturnType();
+ mirror::Class* result_type = h_interface_method->GetArtMethod()->GetReturnType();
mirror::Object* result_ref = soa.Decode<mirror::Object*>(result);
JValue result_unboxed;
if (!UnboxPrimitiveForResult(result_ref, result_type, &result_unboxed)) {
@@ -293,10 +293,9 @@
if (exception->IsCheckedException()) {
mirror::Object* rcvr = soa.Decode<mirror::Object*>(rcvr_jobj);
mirror::Class* proxy_class = rcvr->GetClass();
- mirror::ArtMethod* interface_method =
- soa.Decode<mirror::ArtMethod*>(interface_method_jobj);
+ mirror::Method* interface_method = soa.Decode<mirror::Method*>(interface_method_jobj);
mirror::ArtMethod* proxy_method =
- rcvr->GetClass()->FindVirtualMethodForInterface(interface_method);
+ rcvr->GetClass()->FindVirtualMethodForInterface(interface_method->GetArtMethod());
int throws_index = -1;
size_t num_virt_methods = proxy_class->NumVirtualMethods();
for (size_t i = 0; i < num_virt_methods; i++) {
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index 2e813c8..2e7e2df 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -26,6 +26,7 @@
#include "mirror/art_method-inl.h"
#include "mirror/class-inl.h"
#include "mirror/dex_cache-inl.h"
+#include "mirror/method.h"
#include "mirror/object-inl.h"
#include "mirror/object_array-inl.h"
#include "runtime.h"
@@ -760,11 +761,12 @@
mirror::ArtMethod* interface_method = proxy_method->FindOverriddenMethod();
DCHECK(interface_method != nullptr) << PrettyMethod(proxy_method);
DCHECK(!interface_method->IsProxyMethod()) << PrettyMethod(interface_method);
- jobject interface_method_jobj = soa.AddLocalReference<jobject>(interface_method);
+ self->EndAssertNoThreadSuspension(old_cause);
+ jobject interface_method_jobj = soa.AddLocalReference<jobject>(
+ mirror::Method::CreateFromArtMethod(soa.Self(), interface_method));
// All naked Object*s should now be in jobjects, so its safe to go into the main invoke code
// that performs allocations.
- self->EndAssertNoThreadSuspension(old_cause);
JValue result = InvokeProxyInvocationHandler(soa, shorty, rcvr_jobj, interface_method_jobj, args);
// Restore references which might have moved.
local_ref_visitor.FixupReferences();
diff --git a/runtime/intern_table.cc b/runtime/intern_table.cc
index 1f1f9e8..4c5fc81 100644
--- a/runtime/intern_table.cc
+++ b/runtime/intern_table.cc
@@ -236,11 +236,6 @@
if (strong != nullptr) {
return strong;
}
- // Check the image for a match.
- mirror::String* image = LookupStringFromImage(s);
- if (image != nullptr) {
- return is_strong ? InsertStrong(image) : InsertWeak(image);
- }
// There is no match in the strong table, check the weak table.
mirror::String* weak = LookupWeak(s);
if (weak != nullptr) {
@@ -251,6 +246,11 @@
}
return weak;
}
+ // Check the image for a match.
+ mirror::String* image = LookupStringFromImage(s);
+ if (image != nullptr) {
+ return is_strong ? InsertStrong(image) : InsertWeak(image);
+ }
// No match in the strong table or the weak table. Insert into the strong / weak table.
return is_strong ? InsertStrong(s) : InsertWeak(s);
}
diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc
index 8a5461b..554a28d 100644
--- a/runtime/jni_internal.cc
+++ b/runtime/jni_internal.cc
@@ -42,6 +42,7 @@
#include "mirror/class-inl.h"
#include "mirror/class_loader.h"
#include "mirror/field-inl.h"
+#include "mirror/method.h"
#include "mirror/object-inl.h"
#include "mirror/object_array-inl.h"
#include "mirror/string-inl.h"
@@ -361,19 +362,13 @@
ScopedObjectAccess soa(env);
mirror::ArtMethod* m = soa.DecodeMethod(mid);
CHECK(!kMovingMethods);
- ScopedLocalRef<jobject> art_method(env, soa.AddLocalReference<jobject>(m));
- jobject reflect_method;
+ mirror::AbstractMethod* method;
if (m->IsConstructor()) {
- reflect_method = env->AllocObject(WellKnownClasses::java_lang_reflect_Constructor);
+ method = mirror::Constructor::CreateFromArtMethod(soa.Self(), m);
} else {
- reflect_method = env->AllocObject(WellKnownClasses::java_lang_reflect_Method);
+ method = mirror::Method::CreateFromArtMethod(soa.Self(), m);
}
- if (env->ExceptionCheck()) {
- return nullptr;
- }
- SetObjectField(env, reflect_method,
- WellKnownClasses::java_lang_reflect_AbstractMethod_artMethod, art_method.get());
- return reflect_method;
+ return soa.AddLocalReference<jobject>(method);
}
static jobject ToReflectedField(JNIEnv* env, jclass, jfieldID fid, jboolean) {
diff --git a/runtime/mirror/abstract_method.cc b/runtime/mirror/abstract_method.cc
new file mode 100644
index 0000000..81c656b
--- /dev/null
+++ b/runtime/mirror/abstract_method.cc
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#include "abstract_method.h"
+
+#include "mirror/art_method-inl.h"
+
+namespace art {
+namespace mirror {
+
+bool AbstractMethod::CreateFromArtMethod(mirror::ArtMethod* method) {
+ auto* interface_method = method->GetInterfaceMethodIfProxy();
+ SetFieldObject<false>(ArtMethodOffset(), method);
+ SetFieldObject<false>(DeclaringClassOffset(), method->GetDeclaringClass());
+ SetFieldObject<false>(
+ DeclaringClassOfOverriddenMethodOffset(), interface_method->GetDeclaringClass());
+ SetField32<false>(AccessFlagsOffset(), method->GetAccessFlags());
+ SetField32<false>(DexMethodIndexOffset(), method->GetDexMethodIndex());
+ return true;
+}
+
+mirror::ArtMethod* AbstractMethod::GetArtMethod() {
+ return GetFieldObject<mirror::ArtMethod>(ArtMethodOffset());
+}
+
+mirror::Class* AbstractMethod::GetDeclaringClass() {
+ return GetFieldObject<mirror::Class>(DeclaringClassOffset());
+}
+
+} // namespace mirror
+} // namespace art
diff --git a/runtime/mirror/abstract_method.h b/runtime/mirror/abstract_method.h
new file mode 100644
index 0000000..ef51d7f
--- /dev/null
+++ b/runtime/mirror/abstract_method.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2015 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 "accessible_object.h"
+#include "gc_root.h"
+#include "object.h"
+#include "object_callbacks.h"
+#include "read_barrier_option.h"
+
+namespace art {
+
+struct AbstractMethodOffsets;
+
+namespace mirror {
+
+class ArtMethod;
+
+// C++ mirror of java.lang.reflect.AbstractMethod.
+class MANAGED AbstractMethod : public AccessibleObject {
+ public:
+ // Called from Constructor::CreateFromArtMethod, Method::CreateFromArtMethod.
+ bool CreateFromArtMethod(mirror::ArtMethod* method) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ mirror::ArtMethod* GetArtMethod() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ mirror::Class* GetDeclaringClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ private:
+ static MemberOffset ArtMethodOffset() {
+ return MemberOffset(OFFSETOF_MEMBER(AbstractMethod, art_method_));
+ }
+ static MemberOffset DeclaringClassOffset() {
+ return MemberOffset(OFFSETOF_MEMBER(AbstractMethod, declaring_class_));
+ }
+ static MemberOffset DeclaringClassOfOverriddenMethodOffset() {
+ return MemberOffset(OFFSETOF_MEMBER(AbstractMethod, declaring_class_of_overridden_method_));
+ }
+ static MemberOffset AccessFlagsOffset() {
+ return MemberOffset(OFFSETOF_MEMBER(AbstractMethod, access_flags_));
+ }
+ static MemberOffset DexMethodIndexOffset() {
+ return MemberOffset(OFFSETOF_MEMBER(AbstractMethod, dex_method_index_));
+ }
+
+ HeapReference<mirror::ArtMethod> art_method_;
+ HeapReference<mirror::Class> declaring_class_;
+ HeapReference<mirror::Class> declaring_class_of_overridden_method_;
+ uint32_t access_flags_;
+ uint32_t dex_method_index_;
+
+ friend struct art::AbstractMethodOffsets; // for verifying offset information
+ DISALLOW_IMPLICIT_CONSTRUCTORS(AbstractMethod);
+};
+
+} // namespace mirror
+} // namespace art
+
+#endif // ART_RUNTIME_MIRROR_ABSTRACT_METHOD_H_
diff --git a/runtime/mirror/art_method-inl.h b/runtime/mirror/art_method-inl.h
index a300d52..5fc96ad 100644
--- a/runtime/mirror/art_method-inl.h
+++ b/runtime/mirror/art_method-inl.h
@@ -36,7 +36,7 @@
namespace mirror {
inline uint32_t ArtMethod::ClassSize() {
- uint32_t vtable_entries = Object::kVTableLength + 7;
+ uint32_t vtable_entries = Object::kVTableLength;
return Class::ComputeClassSize(true, vtable_entries, 0, 0, 0, 0, 0);
}
diff --git a/runtime/mirror/art_method.cc b/runtime/mirror/art_method.cc
index 92aea1f..9483ba6 100644
--- a/runtime/mirror/art_method.cc
+++ b/runtime/mirror/art_method.cc
@@ -16,6 +16,7 @@
#include "art_method.h"
+#include "abstract_method.h"
#include "arch/context.h"
#include "art_field-inl.h"
#include "art_method-inl.h"
@@ -53,14 +54,11 @@
ArtMethod* ArtMethod::FromReflectedMethod(const ScopedObjectAccessAlreadyRunnable& soa,
jobject jlr_method) {
- ArtField* f =
- soa.DecodeField(WellKnownClasses::java_lang_reflect_AbstractMethod_artMethod);
- mirror::ArtMethod* method = f->GetObject(soa.Decode<mirror::Object*>(jlr_method))->AsArtMethod();
- DCHECK(method != nullptr);
- return method;
+ auto* abstract_method = soa.Decode<mirror::AbstractMethod*>(jlr_method);
+ DCHECK(abstract_method != nullptr);
+ return abstract_method->GetArtMethod();
}
-
void ArtMethod::VisitRoots(RootVisitor* visitor) {
java_lang_reflect_ArtMethod_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass));
}
@@ -547,5 +545,31 @@
RegisterNative(GetJniDlsymLookupStub(), false);
}
+bool ArtMethod::EqualParameters(Handle<mirror::ObjectArray<mirror::Class>> params) {
+ auto* dex_cache = GetDexCache();
+ auto* dex_file = dex_cache->GetDexFile();
+ const auto& method_id = dex_file->GetMethodId(GetDexMethodIndex());
+ const auto& proto_id = dex_file->GetMethodPrototype(method_id);
+ const DexFile::TypeList* proto_params = dex_file->GetProtoParameters(proto_id);
+ auto count = proto_params != nullptr ? proto_params->Size() : 0u;
+ auto param_len = params.Get() != nullptr ? params->GetLength() : 0u;
+ if (param_len != count) {
+ return false;
+ }
+ auto* cl = Runtime::Current()->GetClassLinker();
+ for (size_t i = 0; i < count; ++i) {
+ auto type_idx = proto_params->GetTypeItem(i).type_idx_;
+ auto* type = cl->ResolveType(type_idx, this);
+ if (type == nullptr) {
+ Thread::Current()->AssertPendingException();
+ return false;
+ }
+ if (type != params->GetWithoutChecks(i)) {
+ return false;
+ }
+ }
+ return true;
+}
+
} // namespace mirror
} // namespace art
diff --git a/runtime/mirror/art_method.h b/runtime/mirror/art_method.h
index 55b8068..b899b25 100644
--- a/runtime/mirror/art_method.h
+++ b/runtime/mirror/art_method.h
@@ -541,6 +541,10 @@
ALWAYS_INLINE ArtMethod* GetInterfaceMethodIfProxy() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ // May cause thread suspension due to class resolution.
+ bool EqualParameters(Handle<mirror::ObjectArray<mirror::Class>> params)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
static size_t SizeWithoutPointerFields(size_t pointer_size) {
size_t total = sizeof(ArtMethod) - sizeof(PtrSizedFields);
#ifdef ART_METHOD_HAS_PADDING_FIELD_ON_64_BIT
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc
index 2afb4af..1739019 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -25,6 +25,7 @@
#include "dex_file-inl.h"
#include "gc/accounting/card_table-inl.h"
#include "handle_scope-inl.h"
+#include "method.h"
#include "object_array-inl.h"
#include "object-inl.h"
#include "runtime.h"
@@ -876,5 +877,26 @@
return Runtime::Current()->GetClassLinker()->GetDescriptorForProxy(this) == match;
}
+mirror::ArtMethod* Class::GetDeclaredConstructor(
+ Thread* self, Handle<mirror::ObjectArray<mirror::Class>> args) {
+ auto* direct_methods = GetDirectMethods();
+ size_t count = direct_methods != nullptr ? direct_methods->GetLength() : 0u;
+ for (size_t i = 0; i < count; ++i) {
+ auto* m = direct_methods->GetWithoutChecks(i);
+ // Skip <clinit> which is a static constructor, as well as non constructors.
+ if (m->IsStatic() || !m->IsConstructor()) {
+ continue;
+ }
+ // May cause thread suspension and exceptions.
+ if (m->EqualParameters(args)) {
+ return m;
+ }
+ if (self->IsExceptionPending()) {
+ return nullptr;
+ }
+ }
+ return nullptr;
+}
+
} // namespace mirror
} // namespace art
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index 20f2387..5005346 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -47,6 +47,7 @@
class ArtMethod;
class ClassLoader;
+class Constructor;
class DexCache;
class IfTable;
@@ -1052,6 +1053,11 @@
return OFFSET_OF_OBJECT_MEMBER(Class, dex_cache_strings_);
}
+ // May cause thread suspension due to EqualParameters.
+ mirror::ArtMethod* GetDeclaredConstructor(
+ Thread* self, Handle<mirror::ObjectArray<mirror::Class>> args)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
// Used to initialize a class in the allocation code path to ensure it is guarded by a StoreStore
// fence.
class InitializeClassVisitor {
diff --git a/runtime/mirror/field.h b/runtime/mirror/field.h
index 9988f84..d927f0c 100644
--- a/runtime/mirror/field.h
+++ b/runtime/mirror/field.h
@@ -82,15 +82,12 @@
}
static void SetClass(Class* klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
- static void SetArrayClass(Class* klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
static void ResetClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ static void SetArrayClass(Class* klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
static void ResetArrayClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- static void VisitRoots(RootVisitor* visitor)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ static void VisitRoots(RootVisitor* visitor) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Slow, try to use only for PrettyField and such.
ArtField* GetArtField() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/runtime/mirror/method.cc b/runtime/mirror/method.cc
new file mode 100644
index 0000000..81530bb
--- /dev/null
+++ b/runtime/mirror/method.cc
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#include "method.h"
+
+#include "mirror/art_method.h"
+#include "mirror/object-inl.h"
+
+namespace art {
+namespace mirror {
+
+GcRoot<Class> Method::static_class_;
+GcRoot<Class> Method::array_class_;
+GcRoot<Class> Constructor::static_class_;
+GcRoot<Class> Constructor::array_class_;
+
+void Method::SetClass(Class* klass) {
+ CHECK(static_class_.IsNull()) << static_class_.Read() << " " << klass;
+ CHECK(klass != nullptr);
+ static_class_ = GcRoot<Class>(klass);
+}
+
+void Method::ResetClass() {
+ CHECK(!static_class_.IsNull());
+ static_class_ = GcRoot<Class>(nullptr);
+}
+
+void Method::SetArrayClass(Class* klass) {
+ CHECK(array_class_.IsNull()) << array_class_.Read() << " " << klass;
+ CHECK(klass != nullptr);
+ array_class_ = GcRoot<Class>(klass);
+}
+
+void Method::ResetArrayClass() {
+ CHECK(!array_class_.IsNull());
+ array_class_ = GcRoot<Class>(nullptr);
+}
+
+Method* Method::CreateFromArtMethod(Thread* self, mirror::ArtMethod* method) {
+ DCHECK(!method->IsConstructor()) << PrettyMethod(method);
+ auto* ret = down_cast<Method*>(StaticClass()->AllocObject(self));
+ if (LIKELY(ret != nullptr)) {
+ static_cast<AbstractMethod*>(ret)->CreateFromArtMethod(method);
+ }
+ return ret;
+}
+
+void Method::VisitRoots(RootVisitor* visitor) {
+ static_class_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass));
+ array_class_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass));
+}
+
+void Constructor::SetClass(Class* klass) {
+ CHECK(static_class_.IsNull()) << static_class_.Read() << " " << klass;
+ CHECK(klass != nullptr);
+ static_class_ = GcRoot<Class>(klass);
+}
+
+void Constructor::ResetClass() {
+ CHECK(!static_class_.IsNull());
+ static_class_ = GcRoot<Class>(nullptr);
+}
+
+void Constructor::SetArrayClass(Class* klass) {
+ CHECK(array_class_.IsNull()) << array_class_.Read() << " " << klass;
+ CHECK(klass != nullptr);
+ array_class_ = GcRoot<Class>(klass);
+}
+
+void Constructor::ResetArrayClass() {
+ CHECK(!array_class_.IsNull());
+ array_class_ = GcRoot<Class>(nullptr);
+}
+
+void Constructor::VisitRoots(RootVisitor* visitor) {
+ static_class_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass));
+ array_class_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass));
+}
+
+Constructor* Constructor::CreateFromArtMethod(Thread* self, mirror::ArtMethod* method) {
+ DCHECK(method->IsConstructor()) << PrettyMethod(method);
+ auto* ret = down_cast<Constructor*>(StaticClass()->AllocObject(self));
+ if (LIKELY(ret != nullptr)) {
+ static_cast<AbstractMethod*>(ret)->CreateFromArtMethod(method);
+ }
+ return ret;
+}
+
+} // namespace mirror
+} // namespace art
diff --git a/runtime/mirror/method.h b/runtime/mirror/method.h
new file mode 100644
index 0000000..88100f0
--- /dev/null
+++ b/runtime/mirror/method.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2015 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_METHOD_H_
+#define ART_RUNTIME_MIRROR_METHOD_H_
+
+#include "abstract_method.h"
+#include "gc_root.h"
+
+namespace art {
+namespace mirror {
+
+class Class;
+
+// C++ mirror of java.lang.reflect.Method.
+class MANAGED Method : public AbstractMethod {
+ public:
+ static Method* CreateFromArtMethod(Thread* self, mirror::ArtMethod* method)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ static mirror::Class* StaticClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ return static_class_.Read();
+ }
+
+ static void SetClass(Class* klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ static void ResetClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ static mirror::Class* ArrayClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ return array_class_.Read();
+ }
+
+ static void SetArrayClass(Class* klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ static void ResetArrayClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ static void VisitRoots(RootVisitor* visitor) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ private:
+ static GcRoot<Class> static_class_; // java.lang.reflect.Method.class.
+ static GcRoot<Class> array_class_; // [java.lang.reflect.Method.class.
+
+ DISALLOW_COPY_AND_ASSIGN(Method);
+};
+
+// C++ mirror of java.lang.reflect.Constructor.
+class MANAGED Constructor: public AbstractMethod {
+ public:
+ static Constructor* CreateFromArtMethod(Thread* self, mirror::ArtMethod* method)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ static mirror::Class* StaticClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ return static_class_.Read();
+ }
+
+ static void SetClass(Class* klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ static void ResetClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ static mirror::Class* ArrayClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ return array_class_.Read();
+ }
+
+ static void SetArrayClass(Class* klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ static void ResetArrayClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ static void VisitRoots(RootVisitor* visitor) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ private:
+ static GcRoot<Class> static_class_; // java.lang.reflect.Constructor.class.
+ static GcRoot<Class> array_class_; // [java.lang.reflect.Constructor.class.
+
+ DISALLOW_COPY_AND_ASSIGN(Constructor);
+};
+
+} // namespace mirror
+} // namespace art
+
+#endif // ART_RUNTIME_MIRROR_METHOD_H_
diff --git a/runtime/native/dalvik_system_VMStack.cc b/runtime/native/dalvik_system_VMStack.cc
index 2cdc68f..17fbc4f 100644
--- a/runtime/native/dalvik_system_VMStack.cc
+++ b/runtime/native/dalvik_system_VMStack.cc
@@ -81,33 +81,26 @@
return soa.AddLocalReference<jobject>(visitor.caller->GetDeclaringClass()->GetClassLoader());
}
-static jobject VMStack_getClosestUserClassLoader(JNIEnv* env, jclass, jobject javaBootstrap,
- jobject javaSystem) {
+static jobject VMStack_getClosestUserClassLoader(JNIEnv* env, jclass) {
struct ClosestUserClassLoaderVisitor : public StackVisitor {
- ClosestUserClassLoaderVisitor(Thread* thread, mirror::Object* bootstrap_in,
- mirror::Object* system_in)
- : StackVisitor(thread, NULL), bootstrap(bootstrap_in), system(system_in),
- class_loader(NULL) {}
+ explicit ClosestUserClassLoaderVisitor(Thread* thread)
+ : StackVisitor(thread, nullptr), class_loader(nullptr) {}
bool VisitFrame() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- DCHECK(class_loader == NULL);
+ DCHECK(class_loader == nullptr);
mirror::Class* c = GetMethod()->GetDeclaringClass();
mirror::Object* cl = c->GetClassLoader();
- if (cl != NULL && cl != bootstrap && cl != system) {
+ if (cl != nullptr) {
class_loader = cl;
return false;
}
return true;
}
- mirror::Object* bootstrap;
- mirror::Object* system;
mirror::Object* class_loader;
};
ScopedFastNativeObjectAccess soa(env);
- mirror::Object* bootstrap = soa.Decode<mirror::Object*>(javaBootstrap);
- mirror::Object* system = soa.Decode<mirror::Object*>(javaSystem);
- ClosestUserClassLoaderVisitor visitor(soa.Self(), bootstrap, system);
+ ClosestUserClassLoaderVisitor visitor(soa.Self());
visitor.WalkStack();
return soa.AddLocalReference<jobject>(visitor.class_loader);
}
@@ -136,7 +129,7 @@
static JNINativeMethod gMethods[] = {
NATIVE_METHOD(VMStack, fillStackTraceElements, "!(Ljava/lang/Thread;[Ljava/lang/StackTraceElement;)I"),
NATIVE_METHOD(VMStack, getCallingClassLoader, "!()Ljava/lang/ClassLoader;"),
- NATIVE_METHOD(VMStack, getClosestUserClassLoader, "!(Ljava/lang/ClassLoader;Ljava/lang/ClassLoader;)Ljava/lang/ClassLoader;"),
+ NATIVE_METHOD(VMStack, getClosestUserClassLoader, "!()Ljava/lang/ClassLoader;"),
NATIVE_METHOD(VMStack, getStackClass2, "!()Ljava/lang/Class;"),
NATIVE_METHOD(VMStack, getThreadStackTrace, "!(Ljava/lang/Thread;)[Ljava/lang/StackTraceElement;"),
};
diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc
index 5ad18f8..51a897d 100644
--- a/runtime/native/java_lang_Class.cc
+++ b/runtime/native/java_lang_Class.cc
@@ -25,6 +25,7 @@
#include "mirror/class-inl.h"
#include "mirror/class_loader.h"
#include "mirror/field-inl.h"
+#include "mirror/method.h"
#include "mirror/object-inl.h"
#include "mirror/object_array-inl.h"
#include "mirror/string-inl.h"
@@ -91,18 +92,6 @@
return soa.AddLocalReference<jclass>(c.Get());
}
-static jobject Class_findOverriddenMethodIfProxy(JNIEnv* env, jclass, jobject art_method) {
- ScopedFastNativeObjectAccess soa(env);
- mirror::ArtMethod* method = soa.Decode<mirror::ArtMethod*>(art_method);
- mirror::Class* declaring_klass = method->GetDeclaringClass();
- if (!declaring_klass->IsProxyClass()) {
- return art_method;
- }
- uint32_t dex_method_index = method->GetDexMethodIndex();
- mirror::ArtMethod* overriden_method = method->GetDexCacheResolvedMethods()->Get(dex_method_index);
- return soa.AddLocalReference<jobject>(overriden_method);
-}
-
static jstring Class_getNameNative(JNIEnv* env, jobject javaThis) {
ScopedFastNativeObjectAccess soa(env);
StackHandleScope<1> hs(soa.Self());
@@ -252,7 +241,7 @@
static jobject Class_getDeclaredField(JNIEnv* env, jobject javaThis, jstring name) {
ScopedFastNativeObjectAccess soa(env);
auto* name_string = soa.Decode<mirror::String*>(name);
- if (name == nullptr) {
+ if (name_string == nullptr) {
ThrowNullPointerException("name == null");
return nullptr;
}
@@ -269,17 +258,222 @@
return soa.AddLocalReference<jobject>(result);
}
+static jobject Class_getDeclaredConstructorInternal(
+ JNIEnv* env, jobject javaThis, jobjectArray args) {
+ ScopedFastNativeObjectAccess soa(env);
+ auto* klass = DecodeClass(soa, javaThis);
+ auto* params = soa.Decode<mirror::ObjectArray<mirror::Class>*>(args);
+ StackHandleScope<1> hs(soa.Self());
+ auto* declared_constructor = klass->GetDeclaredConstructor(soa.Self(), hs.NewHandle(params));
+ if (declared_constructor != nullptr) {
+ return soa.AddLocalReference<jobject>(
+ mirror::Constructor::CreateFromArtMethod(soa.Self(), declared_constructor));
+ }
+ return nullptr;
+}
+
+static ALWAYS_INLINE inline bool MethodMatchesConstructor(mirror::ArtMethod* m, bool public_only)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ DCHECK(m != nullptr);
+ return (!public_only || m->IsPublic()) && !m->IsStatic() && m->IsConstructor();
+}
+
+static jobjectArray Class_getDeclaredConstructorsInternal(
+ JNIEnv* env, jobject javaThis, jboolean publicOnly) {
+ ScopedFastNativeObjectAccess soa(env);
+ auto* klass = DecodeClass(soa, javaThis);
+ StackHandleScope<2> hs(soa.Self());
+ auto h_direct_methods = hs.NewHandle(klass->GetDirectMethods());
+ size_t constructor_count = 0;
+ auto count = h_direct_methods.Get() != nullptr ? h_direct_methods->GetLength() : 0u;
+ // Two pass approach for speed.
+ for (size_t i = 0; i < count; ++i) {
+ constructor_count += MethodMatchesConstructor(h_direct_methods->GetWithoutChecks(i),
+ publicOnly != JNI_FALSE) ? 1u : 0u;
+ }
+ auto h_constructors = hs.NewHandle(mirror::ObjectArray<mirror::Constructor>::Alloc(
+ soa.Self(), mirror::Constructor::ArrayClass(), constructor_count));
+ if (UNLIKELY(h_constructors.Get() == nullptr)) {
+ soa.Self()->AssertPendingException();
+ return nullptr;
+ }
+ constructor_count = 0;
+ for (size_t i = 0; i < count; ++i) {
+ auto* method = h_direct_methods->GetWithoutChecks(i);
+ if (MethodMatchesConstructor(method, publicOnly != JNI_FALSE)) {
+ auto* constructor = mirror::Constructor::CreateFromArtMethod(soa.Self(), method);
+ if (UNLIKELY(constructor == nullptr)) {
+ soa.Self()->AssertPendingException();
+ return nullptr;
+ }
+ h_constructors->SetWithoutChecks<false>(constructor_count++, constructor);
+ }
+ }
+ return soa.AddLocalReference<jobjectArray>(h_constructors.Get());
+}
+
+static jobject Class_getDeclaredMethodInternal(JNIEnv* env, jobject javaThis,
+ jobject name, jobjectArray args) {
+ // Covariant return types permit the class to define multiple
+ // methods with the same name and parameter types. Prefer to
+ // return a non-synthetic method in such situations. We may
+ // still return a synthetic method to handle situations like
+ // escalated visibility. We never return miranda methods that
+ // were synthesized by the runtime.
+ constexpr uint32_t kSkipModifiers = kAccMiranda | kAccSynthetic;
+ ScopedFastNativeObjectAccess soa(env);
+ StackHandleScope<5> hs(soa.Self());
+ auto h_method_name = hs.NewHandle(soa.Decode<mirror::String*>(name));
+ if (UNLIKELY(h_method_name.Get() == nullptr)) {
+ ThrowNullPointerException("name == null");
+ return nullptr;
+ }
+ auto h_args = hs.NewHandle(soa.Decode<mirror::ObjectArray<mirror::Class>*>(args));
+ auto* klass = DecodeClass(soa, javaThis);
+ mirror::ArtMethod* result = nullptr;
+ auto* virtual_methods = klass->GetVirtualMethods();
+ if (virtual_methods != nullptr) {
+ auto h_virtual_methods = hs.NewHandle(virtual_methods);
+ for (size_t i = 0, count = virtual_methods->GetLength(); i < count; ++i) {
+ auto* m = h_virtual_methods->GetWithoutChecks(i);
+ auto* np_method = m->GetInterfaceMethodIfProxy();
+ // May cause thread suspension.
+ mirror::String* np_name = np_method->GetNameAsString(soa.Self());
+ if (!np_name->Equals(h_method_name.Get()) || !np_method->EqualParameters(h_args)) {
+ if (UNLIKELY(soa.Self()->IsExceptionPending())) {
+ return nullptr;
+ }
+ continue;
+ }
+ auto modifiers = m->GetAccessFlags();
+ if ((modifiers & kSkipModifiers) == 0) {
+ return soa.AddLocalReference<jobject>(mirror::Method::CreateFromArtMethod(soa.Self(), m));
+ }
+ if ((modifiers & kAccMiranda) == 0) {
+ result = m; // Remember as potential result if it's not a miranda method.
+ }
+ }
+ }
+ if (result == nullptr) {
+ auto* direct_methods = klass->GetDirectMethods();
+ if (direct_methods != nullptr) {
+ auto h_direct_methods = hs.NewHandle(direct_methods);
+ for (size_t i = 0, count = direct_methods->GetLength(); i < count; ++i) {
+ auto* m = h_direct_methods->GetWithoutChecks(i);
+ auto modifiers = m->GetAccessFlags();
+ if ((modifiers & kAccConstructor) != 0) {
+ continue;
+ }
+ auto* np_method = m->GetInterfaceMethodIfProxy();
+ // May cause thread suspension.
+ mirror::String* np_name = np_method ->GetNameAsString(soa.Self());
+ if (np_name == nullptr) {
+ soa.Self()->AssertPendingException();
+ return nullptr;
+ }
+ if (!np_name->Equals(h_method_name.Get()) || !np_method->EqualParameters(h_args)) {
+ if (UNLIKELY(soa.Self()->IsExceptionPending())) {
+ return nullptr;
+ }
+ continue;
+ }
+ if ((modifiers & kSkipModifiers) == 0) {
+ return soa.AddLocalReference<jobject>(mirror::Method::CreateFromArtMethod(
+ soa.Self(), m));
+ }
+ // Direct methods cannot be miranda methods, so this potential result must be synthetic.
+ result = m;
+ }
+ }
+ }
+ return result != nullptr ?
+ soa.AddLocalReference<jobject>(mirror::Method::CreateFromArtMethod(soa.Self(), result)) :
+ nullptr;
+}
+
+jobjectArray Class_getDeclaredMethodsUnchecked(JNIEnv* env, jobject javaThis,
+ jboolean publicOnly) {
+ ScopedFastNativeObjectAccess soa(env);
+ StackHandleScope<5> hs(soa.Self());
+ auto* klass = DecodeClass(soa, javaThis);
+ auto virtual_methods = hs.NewHandle(klass->GetVirtualMethods());
+ auto direct_methods = hs.NewHandle(klass->GetDirectMethods());
+ size_t num_methods = 0;
+ if (virtual_methods.Get() != nullptr) {
+ for (size_t i = 0, count = virtual_methods->GetLength(); i < count; ++i) {
+ auto* m = virtual_methods->GetWithoutChecks(i);
+ auto modifiers = m->GetAccessFlags();
+ if ((publicOnly == JNI_FALSE || (modifiers & kAccPublic) != 0) &&
+ (modifiers & kAccMiranda) == 0) {
+ ++num_methods;
+ }
+ }
+ }
+ if (direct_methods.Get() != nullptr) {
+ for (size_t i = 0, count = direct_methods->GetLength(); i < count; ++i) {
+ auto* m = direct_methods->GetWithoutChecks(i);
+ auto modifiers = m->GetAccessFlags();
+ // Add non-constructor direct/static methods.
+ if ((publicOnly == JNI_FALSE || (modifiers & kAccPublic) != 0) &&
+ (modifiers & kAccConstructor) == 0) {
+ ++num_methods;
+ }
+ }
+ }
+ auto ret = hs.NewHandle(mirror::ObjectArray<mirror::Method>::Alloc(
+ soa.Self(), mirror::Method::ArrayClass(), num_methods));
+ num_methods = 0;
+ if (virtual_methods.Get() != nullptr) {
+ for (size_t i = 0, count = virtual_methods->GetLength(); i < count; ++i) {
+ auto* m = virtual_methods->GetWithoutChecks(i);
+ auto modifiers = m->GetAccessFlags();
+ if ((publicOnly == JNI_FALSE || (modifiers & kAccPublic) != 0) &&
+ (modifiers & kAccMiranda) == 0) {
+ auto* method = mirror::Method::CreateFromArtMethod(soa.Self(), m);
+ if (method == nullptr) {
+ soa.Self()->AssertPendingException();
+ return nullptr;
+ }
+ ret->SetWithoutChecks<false>(num_methods++, method);
+ }
+ }
+ }
+ if (direct_methods.Get() != nullptr) {
+ for (size_t i = 0, count = direct_methods->GetLength(); i < count; ++i) {
+ auto* m = direct_methods->GetWithoutChecks(i);
+ auto modifiers = m->GetAccessFlags();
+ // Add non-constructor direct/static methods.
+ if ((publicOnly == JNI_FALSE || (modifiers & kAccPublic) != 0) &&
+ (modifiers & kAccConstructor) == 0) {
+ auto* method = mirror::Method::CreateFromArtMethod(soa.Self(), m);
+ if (method == nullptr) {
+ soa.Self()->AssertPendingException();
+ return nullptr;
+ }
+ ret->SetWithoutChecks<false>(num_methods++, method);
+ }
+ }
+ }
+ return soa.AddLocalReference<jobjectArray>(ret.Get());
+}
+
static JNINativeMethod gMethods[] = {
- NATIVE_METHOD(Class, classForName, "!(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;"),
- NATIVE_METHOD(Class, findOverriddenMethodIfProxy,
- "!(Ljava/lang/reflect/ArtMethod;)Ljava/lang/reflect/ArtMethod;"),
+ NATIVE_METHOD(Class, classForName,
+ "!(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;"),
+ NATIVE_METHOD(Class, getDeclaredConstructorInternal,
+ "!([Ljava/lang/Class;)Ljava/lang/reflect/Constructor;"),
+ NATIVE_METHOD(Class, getDeclaredConstructorsInternal, "!(Z)[Ljava/lang/reflect/Constructor;"),
+ NATIVE_METHOD(Class, getDeclaredField, "!(Ljava/lang/String;)Ljava/lang/reflect/Field;"),
+ NATIVE_METHOD(Class, getDeclaredFieldInternal, "!(Ljava/lang/String;)Ljava/lang/reflect/Field;"),
+ NATIVE_METHOD(Class, getDeclaredFields, "!()[Ljava/lang/reflect/Field;"),
+ NATIVE_METHOD(Class, getDeclaredFieldsUnchecked, "!(Z)[Ljava/lang/reflect/Field;"),
+ NATIVE_METHOD(Class, getDeclaredMethodInternal,
+ "!(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;"),
+ NATIVE_METHOD(Class, getDeclaredMethodsUnchecked,
+ "!(Z)[Ljava/lang/reflect/Method;"),
NATIVE_METHOD(Class, getNameNative, "!()Ljava/lang/String;"),
NATIVE_METHOD(Class, getProxyInterfaces, "!()[Ljava/lang/Class;"),
- NATIVE_METHOD(Class, getDeclaredFields, "!()[Ljava/lang/reflect/Field;"),
NATIVE_METHOD(Class, getPublicDeclaredFields, "!()[Ljava/lang/reflect/Field;"),
- NATIVE_METHOD(Class, getDeclaredFieldsUnchecked, "!(Z)[Ljava/lang/reflect/Field;"),
- NATIVE_METHOD(Class, getDeclaredFieldInternal, "!(Ljava/lang/String;)Ljava/lang/reflect/Field;"),
- NATIVE_METHOD(Class, getDeclaredField, "!(Ljava/lang/String;)Ljava/lang/reflect/Field;"),
};
void register_java_lang_Class(JNIEnv* env) {
diff --git a/runtime/native/java_lang_reflect_Constructor.cc b/runtime/native/java_lang_reflect_Constructor.cc
index 5e1a4c5..c33f81a 100644
--- a/runtime/native/java_lang_reflect_Constructor.cc
+++ b/runtime/native/java_lang_reflect_Constructor.cc
@@ -21,6 +21,7 @@
#include "mirror/art_method.h"
#include "mirror/art_method-inl.h"
#include "mirror/class-inl.h"
+#include "mirror/method.h"
#include "mirror/object-inl.h"
#include "reflection.h"
#include "scoped_fast_native_object_access.h"
@@ -28,17 +29,10 @@
namespace art {
-/*
- * We get here through Constructor.newInstance(). The Constructor object
- * would not be available if the constructor weren't public (per the
- * definition of Class.getConstructor), so we can skip the method access
- * check. We can also safely assume the constructor isn't associated
- * with an interface, array, or primitive class.
- */
-static jobject Constructor_newInstance(JNIEnv* env, jobject javaMethod, jobjectArray javaArgs,
- jboolean accessible) {
+static ALWAYS_INLINE inline jobject NewInstanceHelper(
+ JNIEnv* env, jobject javaMethod, jobjectArray javaArgs, size_t num_frames) {
ScopedFastNativeObjectAccess soa(env);
- mirror::ArtMethod* m = mirror::ArtMethod::FromReflectedMethod(soa, javaMethod);
+ mirror::Method* m = soa.Decode<mirror::Method*>(javaMethod);
StackHandleScope<1> hs(soa.Self());
Handle<mirror::Class> c(hs.NewHandle(m->GetDeclaringClass()));
if (UNLIKELY(c->IsAbstract())) {
@@ -67,14 +61,31 @@
}
jobject javaReceiver = soa.AddLocalReference<jobject>(receiver);
- InvokeMethod(soa, javaMethod, javaReceiver, javaArgs, (accessible == JNI_TRUE));
+ InvokeMethod(soa, javaMethod, javaReceiver, javaArgs, num_frames);
// Constructors are ()V methods, so we shouldn't touch the result of InvokeMethod.
return javaReceiver;
}
+/*
+ * We get here through Constructor.newInstance(). The Constructor object
+ * would not be available if the constructor weren't public (per the
+ * definition of Class.getConstructor), so we can skip the method access
+ * check. We can also safely assume the constructor isn't associated
+ * with an interface, array, or primitive class.
+ */
+static jobject Constructor_newInstance(JNIEnv* env, jobject javaMethod, jobjectArray javaArgs) {
+ return NewInstanceHelper(env, javaMethod, javaArgs, 1);
+}
+
+static jobject Constructor_newInstanceTwoFrames(JNIEnv* env, jobject javaMethod,
+ jobjectArray javaArgs) {
+ return NewInstanceHelper(env, javaMethod, javaArgs, 2);
+}
+
static JNINativeMethod gMethods[] = {
- NATIVE_METHOD(Constructor, newInstance, "!([Ljava/lang/Object;Z)Ljava/lang/Object;"),
+ NATIVE_METHOD(Constructor, newInstance, "!([Ljava/lang/Object;)Ljava/lang/Object;"),
+ NATIVE_METHOD(Constructor, newInstanceTwoFrames, "!([Ljava/lang/Object;)Ljava/lang/Object;"),
};
void register_java_lang_reflect_Constructor(JNIEnv* env) {
diff --git a/runtime/native/java_lang_reflect_Method.cc b/runtime/native/java_lang_reflect_Method.cc
index 9859746..c20d832 100644
--- a/runtime/native/java_lang_reflect_Method.cc
+++ b/runtime/native/java_lang_reflect_Method.cc
@@ -30,9 +30,9 @@
namespace art {
static jobject Method_invoke(JNIEnv* env, jobject javaMethod, jobject javaReceiver,
- jobject javaArgs, jboolean accessible) {
+ jobject javaArgs) {
ScopedFastNativeObjectAccess soa(env);
- return InvokeMethod(soa, javaMethod, javaReceiver, javaArgs, (accessible == JNI_TRUE));
+ return InvokeMethod(soa, javaMethod, javaReceiver, javaArgs);
}
static jobject Method_getExceptionTypesNative(JNIEnv* env, jobject javaMethod) {
@@ -55,7 +55,7 @@
}
static JNINativeMethod gMethods[] = {
- NATIVE_METHOD(Method, invoke, "!(Ljava/lang/Object;[Ljava/lang/Object;Z)Ljava/lang/Object;"),
+ NATIVE_METHOD(Method, invoke, "!(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;"),
NATIVE_METHOD(Method, getExceptionTypesNative, "!()[Ljava/lang/Class;"),
};
diff --git a/runtime/native/java_lang_reflect_Proxy.cc b/runtime/native/java_lang_reflect_Proxy.cc
index baf8b24..4a6ab40 100644
--- a/runtime/native/java_lang_reflect_Proxy.cc
+++ b/runtime/native/java_lang_reflect_Proxy.cc
@@ -30,13 +30,12 @@
jobject loader, jobjectArray methods, jobjectArray throws) {
ScopedFastNativeObjectAccess soa(env);
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- mirror::Class* result = class_linker->CreateProxyClass(soa, name, interfaces, loader, methods,
- throws);
- return soa.AddLocalReference<jclass>(result);
+ return soa.AddLocalReference<jclass>(class_linker->CreateProxyClass(
+ soa, name, interfaces, loader, methods, throws));
}
static JNINativeMethod gMethods[] = {
- NATIVE_METHOD(Proxy, generateProxy, "!(Ljava/lang/String;[Ljava/lang/Class;Ljava/lang/ClassLoader;[Ljava/lang/reflect/ArtMethod;[[Ljava/lang/Class;)Ljava/lang/Class;"),
+ NATIVE_METHOD(Proxy, generateProxy, "!(Ljava/lang/String;[Ljava/lang/Class;Ljava/lang/ClassLoader;[Ljava/lang/reflect/Method;[[Ljava/lang/Class;)Ljava/lang/Class;"),
};
void register_java_lang_reflect_Proxy(JNIEnv* env) {
diff --git a/runtime/prebuilt_tools_test.cc b/runtime/prebuilt_tools_test.cc
index 453c0da..53bc876 100644
--- a/runtime/prebuilt_tools_test.cc
+++ b/runtime/prebuilt_tools_test.cc
@@ -49,7 +49,8 @@
}
TEST_F(PrebuiltToolsTest, CheckTargetTools) {
- InstructionSet isas[] = { kArm, kArm64, kThumb2, kX86, kX86_64, kMips, kMips64 }; // NOLINT
+ // Other prebuilts are missing from the build server's repo manifest.
+ InstructionSet isas[] = { kThumb2 }; // NOLINT
for (InstructionSet isa : isas) {
std::string tools_dir = GetAndroidTargetToolsDir(isa);
if (tools_dir.empty()) {
diff --git a/runtime/proxy_test.cc b/runtime/proxy_test.cc
index 6061f73..b471293 100644
--- a/runtime/proxy_test.cc
+++ b/runtime/proxy_test.cc
@@ -20,6 +20,7 @@
#include "art_field-inl.h"
#include "class_linker-inl.h"
#include "common_compiler_test.h"
+#include "mirror/method.h"
#include "scoped_thread_state_change.h"
namespace art {
@@ -53,41 +54,34 @@
mirror::ObjectArray<mirror::ArtMethod>* virtual_methods = interface->GetVirtualMethods();
methods_count += (virtual_methods == nullptr) ? 0 : virtual_methods->GetLength();
}
- jclass javaLangReflectArtMethod =
- soa.AddLocalReference<jclass>(mirror::ArtMethod::GetJavaLangReflectArtMethod());
- jobjectArray proxyClassMethods = soa.Env()->NewObjectArray(methods_count,
- javaLangReflectArtMethod, nullptr);
+ jobjectArray proxyClassMethods = soa.Env()->NewObjectArray(
+ methods_count, soa.AddLocalReference<jclass>(mirror::Method::StaticClass()), nullptr);
soa.Self()->AssertNoPendingException();
- // Fill the method array
- mirror::ArtMethod* equalsMethod = javaLangObject->FindDeclaredVirtualMethod("equals",
- "(Ljava/lang/Object;)Z");
- mirror::ArtMethod* hashCodeMethod = javaLangObject->FindDeclaredVirtualMethod("hashCode",
- "()I");
- mirror::ArtMethod* toStringMethod = javaLangObject->FindDeclaredVirtualMethod("toString",
- "()Ljava/lang/String;");
- CHECK(equalsMethod != nullptr);
- CHECK(hashCodeMethod != nullptr);
- CHECK(toStringMethod != nullptr);
-
jsize array_index = 0;
- // Adds Object methods.
- soa.Env()->SetObjectArrayElement(proxyClassMethods, array_index++,
- soa.AddLocalReference<jobject>(equalsMethod));
- soa.Env()->SetObjectArrayElement(proxyClassMethods, array_index++,
- soa.AddLocalReference<jobject>(hashCodeMethod));
- soa.Env()->SetObjectArrayElement(proxyClassMethods, array_index++,
- soa.AddLocalReference<jobject>(toStringMethod));
-
+ // Fill the method array
+ mirror::ArtMethod* method = javaLangObject->FindDeclaredVirtualMethod(
+ "equals", "(Ljava/lang/Object;)Z");
+ CHECK(method != nullptr);
+ soa.Env()->SetObjectArrayElement(
+ proxyClassMethods, array_index++, soa.AddLocalReference<jobject>(
+ mirror::Method::CreateFromArtMethod(soa.Self(), method)));
+ method = javaLangObject->FindDeclaredVirtualMethod("hashCode", "()I");
+ CHECK(method != nullptr);
+ soa.Env()->SetObjectArrayElement(
+ proxyClassMethods, array_index++, soa.AddLocalReference<jobject>(
+ mirror::Method::CreateFromArtMethod(soa.Self(), method)));
+ method = javaLangObject->FindDeclaredVirtualMethod("toString", "()Ljava/lang/String;");
+ CHECK(method != nullptr);
+ soa.Env()->SetObjectArrayElement(
+ proxyClassMethods, array_index++, soa.AddLocalReference<jobject>(
+ mirror::Method::CreateFromArtMethod(soa.Self(), method)));
// Now adds all interfaces virtual methods.
for (mirror::Class* interface : interfaces) {
- mirror::ObjectArray<mirror::ArtMethod>* virtual_methods = interface->GetVirtualMethods();
- if (virtual_methods != nullptr) {
- for (int32_t mth_index = 0; mth_index < virtual_methods->GetLength(); ++mth_index) {
- mirror::ArtMethod* method = virtual_methods->Get(mth_index);
- soa.Env()->SetObjectArrayElement(proxyClassMethods, array_index++,
- soa.AddLocalReference<jobject>(method));
- }
+ for (int32_t i = 0, count = interface->NumVirtualMethods(); i < count; ++i) {
+ soa.Env()->SetObjectArrayElement(
+ proxyClassMethods, array_index++, soa.AddLocalReference<jobject>(
+ mirror::Method::CreateFromArtMethod(soa.Self(), interface->GetVirtualMethod(i))));
}
}
CHECK_EQ(array_index, methods_count);
@@ -96,10 +90,9 @@
jobjectArray proxyClassThrows = soa.Env()->NewObjectArray(0, javaLangClass, nullptr);
soa.Self()->AssertNoPendingException();
- mirror::Class* proxyClass = class_linker_->CreateProxyClass(soa,
- soa.Env()->NewStringUTF(className),
- proxyClassInterfaces, jclass_loader,
- proxyClassMethods, proxyClassThrows);
+ mirror::Class* proxyClass = class_linker_->CreateProxyClass(
+ soa, soa.Env()->NewStringUTF(className), proxyClassInterfaces, jclass_loader,
+ proxyClassMethods, proxyClassThrows);
soa.Self()->AssertNoPendingException();
return proxyClass;
}
diff --git a/runtime/reflection.cc b/runtime/reflection.cc
index 3e1315c..e546738 100644
--- a/runtime/reflection.cc
+++ b/runtime/reflection.cc
@@ -22,6 +22,7 @@
#include "dex_file-inl.h"
#include "entrypoints/entrypoint_utils.h"
#include "jni_internal.h"
+#include "mirror/abstract_method.h"
#include "mirror/art_method-inl.h"
#include "mirror/class-inl.h"
#include "mirror/object_array-inl.h"
@@ -537,7 +538,7 @@
}
jobject InvokeMethod(const ScopedObjectAccessAlreadyRunnable& soa, jobject javaMethod,
- jobject javaReceiver, jobject javaArgs, bool accessible) {
+ jobject javaReceiver, jobject javaArgs, size_t num_frames) {
// We want to make sure that the stack is not within a small distance from the
// protected region in case we are calling into a leaf function whose stack
// check has been elided.
@@ -547,7 +548,9 @@
return nullptr;
}
- mirror::ArtMethod* m = mirror::ArtMethod::FromReflectedMethod(soa, javaMethod);
+ auto* abstract_method = soa.Decode<mirror::AbstractMethod*>(javaMethod);
+ const bool accessible = abstract_method->IsAccessible();
+ mirror::ArtMethod* m = abstract_method->GetArtMethod();
mirror::Class* declaring_class = m->GetDeclaringClass();
if (UNLIKELY(!declaring_class->IsInitialized())) {
@@ -572,8 +575,7 @@
}
// Get our arrays of arguments and their types, and check they're the same size.
- mirror::ObjectArray<mirror::Object>* objects =
- soa.Decode<mirror::ObjectArray<mirror::Object>*>(javaArgs);
+ auto* objects = soa.Decode<mirror::ObjectArray<mirror::Object>*>(javaArgs);
const DexFile::TypeList* classes = m->GetParameterTypeList();
uint32_t classes_size = (classes == nullptr) ? 0 : classes->Size();
uint32_t arg_count = (objects != nullptr) ? objects->GetLength() : 0;
@@ -586,7 +588,7 @@
// If method is not set to be accessible, verify it can be accessed by the caller.
mirror::Class* calling_class = nullptr;
if (!accessible && !VerifyAccess(soa.Self(), receiver, declaring_class, m->GetAccessFlags(),
- &calling_class, 2)) {
+ &calling_class, num_frames)) {
ThrowIllegalAccessException(
StringPrintf("Class %s cannot access %s method %s of class %s",
calling_class == nullptr ? "null" : PrettyClass(calling_class).c_str(),
diff --git a/runtime/reflection.h b/runtime/reflection.h
index c2d406a..c63f858 100644
--- a/runtime/reflection.h
+++ b/runtime/reflection.h
@@ -65,8 +65,9 @@
JValue* result)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+// num_frames is number of frames we look up for access check.
jobject InvokeMethod(const ScopedObjectAccessAlreadyRunnable& soa, jobject method, jobject receiver,
- jobject args, bool accessible)
+ jobject args, size_t num_frames = 1)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
ALWAYS_INLINE bool VerifyObjectIsClass(mirror::Object* o, mirror::Class* c)
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 7bebb96..2fc8d20 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -77,6 +77,7 @@
#include "mirror/class-inl.h"
#include "mirror/class_loader.h"
#include "mirror/field.h"
+#include "mirror/method.h"
#include "mirror/stack_trace_element.h"
#include "mirror/throwable.h"
#include "monitor.h"
@@ -1308,7 +1309,9 @@
// need to be visited once per GC since they never change.
mirror::ArtMethod::VisitRoots(visitor);
mirror::Class::VisitRoots(visitor);
+ mirror::Constructor::VisitRoots(visitor);
mirror::Reference::VisitRoots(visitor);
+ mirror::Method::VisitRoots(visitor);
mirror::StackTraceElement::VisitRoots(visitor);
mirror::String::VisitRoots(visitor);
mirror::Throwable::VisitRoots(visitor);
diff --git a/runtime/thread.h b/runtime/thread.h
index b095e22..719668b 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -25,6 +25,7 @@
#include <setjmp.h>
#include <string>
+#include "arch/context.h"
#include "arch/instruction_set.h"
#include "atomic.h"
#include "base/macros.h"
@@ -354,7 +355,18 @@
Context* GetLongJumpContext();
void ReleaseLongJumpContext(Context* context) {
- DCHECK(tlsPtr_.long_jump_context == nullptr);
+ if (tlsPtr_.long_jump_context != nullptr) {
+ // Each QuickExceptionHandler gets a long jump context and uses
+ // it for doing the long jump, after finding catch blocks/doing deoptimization.
+ // Both finding catch blocks and deoptimization can trigger another
+ // exception such as a result of class loading. So there can be nested
+ // cases of exception handling and multiple contexts being used.
+ // ReleaseLongJumpContext tries to save the context in tlsPtr_.long_jump_context
+ // for reuse so there is no need to always allocate a new one each time when
+ // getting a context. Since we only keep one context for reuse, delete the
+ // existing one since the passed in context is yet to be used for longjump.
+ delete tlsPtr_.long_jump_context;
+ }
tlsPtr_.long_jump_context = context;
}
diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc
index d389244..f57f9c4 100644
--- a/runtime/well_known_classes.cc
+++ b/runtime/well_known_classes.cc
@@ -212,7 +212,7 @@
ScopedLocalRef<jclass> java_lang_ref_ReferenceQueue(env, env->FindClass("java/lang/ref/ReferenceQueue"));
java_lang_ref_ReferenceQueue_add = CacheMethod(env, java_lang_ref_ReferenceQueue.get(), true, "add", "(Ljava/lang/ref/Reference;)V");
- java_lang_reflect_Proxy_invoke = CacheMethod(env, java_lang_reflect_Proxy, true, "invoke", "(Ljava/lang/reflect/Proxy;Ljava/lang/reflect/ArtMethod;[Ljava/lang/Object;)Ljava/lang/Object;");
+ java_lang_reflect_Proxy_invoke = CacheMethod(env, java_lang_reflect_Proxy, true, "invoke", "(Ljava/lang/reflect/Proxy;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;");
java_lang_Thread_init = CacheMethod(env, java_lang_Thread, false, "<init>", "(Ljava/lang/ThreadGroup;Ljava/lang/String;IZ)V");
java_lang_Thread_run = CacheMethod(env, java_lang_Thread, false, "run", "()V");
java_lang_Thread__UncaughtExceptionHandler_uncaughtException = CacheMethod(env, java_lang_Thread__UncaughtExceptionHandler, false, "uncaughtException", "(Ljava/lang/Thread;Ljava/lang/Throwable;)V");
diff --git a/test/068-classloader/expected.txt b/test/068-classloader/expected.txt
index bf131ee..8725799 100644
--- a/test/068-classloader/expected.txt
+++ b/test/068-classloader/expected.txt
@@ -11,3 +11,5 @@
DoubledImplement one
Got LinkageError on DI (early)
Got LinkageError on IDI (early)
+class Main
+Got expected ClassNotFoundException
diff --git a/test/068-classloader/src-ex/MutationTarget.java b/test/068-classloader/src-ex/MutationTarget.java
new file mode 100644
index 0000000..b02a236
--- /dev/null
+++ b/test/068-classloader/src-ex/MutationTarget.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+/**
+ * Mutator target, see Mutator.java.
+ */
+public class MutationTarget {
+ public static int value = 0;
+}
\ No newline at end of file
diff --git a/test/068-classloader/src-ex/Mutator.java b/test/068-classloader/src-ex/Mutator.java
new file mode 100644
index 0000000..6bcd5b8
--- /dev/null
+++ b/test/068-classloader/src-ex/Mutator.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+/**
+ * Simple mutator to change a static field of the mutator target. This will require a dex-cache
+ * access, so this setup allows the correct disambiguation between multiple class-loaders.
+ */
+public class Mutator {
+ public static void mutate(int v) {
+ MutationTarget.value = v;
+ }
+}
\ No newline at end of file
diff --git a/test/068-classloader/src/Main.java b/test/068-classloader/src/Main.java
index 7dfb6f5..361e293 100644
--- a/test/068-classloader/src/Main.java
+++ b/test/068-classloader/src/Main.java
@@ -21,7 +21,7 @@
/**
* Main entry point.
*/
- public static void main(String[] args) {
+ public static void main(String[] args) throws Exception {
FancyLoader loader;
loader = new FancyLoader(ClassLoader.getSystemClassLoader());
@@ -58,6 +58,65 @@
testAbstract(loader);
testImplement(loader);
testIfaceImplement(loader);
+
+ testSeparation();
+
+ testClassForName();
+ }
+
+ static void testSeparation() {
+ FancyLoader loader1 = new FancyLoader(ClassLoader.getSystemClassLoader());
+ FancyLoader loader2 = new FancyLoader(ClassLoader.getSystemClassLoader());
+
+ try {
+ Class target1 = loader1.loadClass("MutationTarget");
+ Class target2 = loader2.loadClass("MutationTarget");
+
+ if (target1 == target2) {
+ throw new RuntimeException("target1 should not be equal to target2");
+ }
+
+ Class mutator1 = loader1.loadClass("Mutator");
+ Class mutator2 = loader2.loadClass("Mutator");
+
+ if (mutator1 == mutator2) {
+ throw new RuntimeException("mutator1 should not be equal to mutator2");
+ }
+
+ runMutator(mutator1, 1);
+
+ int value = getMutationTargetValue(target1);
+ if (value != 1) {
+ throw new RuntimeException("target 1 has unexpected value " + value);
+ }
+ value = getMutationTargetValue(target2);
+ if (value != 0) {
+ throw new RuntimeException("target 2 has unexpected value " + value);
+ }
+
+ runMutator(mutator2, 2);
+
+ value = getMutationTargetValue(target1);
+ if (value != 1) {
+ throw new RuntimeException("target 1 has unexpected value " + value);
+ }
+ value = getMutationTargetValue(target2);
+ if (value != 2) {
+ throw new RuntimeException("target 2 has unexpected value " + value);
+ }
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+
+ private static void runMutator(Class c, int v) throws Exception {
+ java.lang.reflect.Method m = c.getDeclaredMethod("mutate", int.class);
+ m.invoke(null, v);
+ }
+
+ private static int getMutationTargetValue(Class c) throws Exception {
+ java.lang.reflect.Field f = c.getDeclaredField("value");
+ return f.getInt(null);
}
/**
@@ -422,4 +481,13 @@
DoubledImplement2 di2 = ifaceSuper.getDoubledInstance2();
di2.one();
}
+
+ static void testClassForName() throws Exception {
+ System.out.println(Class.forName("Main").toString());
+ try {
+ System.out.println(Class.forName("Main", false, null).toString());
+ } catch (ClassNotFoundException expected) {
+ System.out.println("Got expected ClassNotFoundException");
+ }
+ }
}
diff --git a/tools/run-jdwp-tests.sh b/tools/run-jdwp-tests.sh
index 301708b..503ec71 100755
--- a/tools/run-jdwp-tests.sh
+++ b/tools/run-jdwp-tests.sh
@@ -81,7 +81,7 @@
--vm-arg -Djpda.settings.verbose=true \
--vm-arg -Djpda.settings.syncPort=34016 \
--vm-arg -Djpda.settings.transportAddress=127.0.0.1:55107 \
- --vm-arg -Djpda.settings.debuggeeJavaPath="$art $image $debuggee_args" \
+ --vm-arg -Djpda.settings.debuggeeJavaPath="\"$art $image $debuggee_args\"" \
--classpath $test_jar \
--classpath $junit_jar \
--vm-arg -Xcompiler-option --vm-arg --compiler-backend=Optimizing \