summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build/Android.common_build.mk5
-rw-r--r--build/art.go3
-rw-r--r--compiler/debug/elf_debug_frame_writer.h7
-rw-r--r--compiler/debug/elf_debug_info_writer.h38
-rw-r--r--compiler/debug/elf_debug_line_writer.h10
-rw-r--r--compiler/debug/elf_debug_loc_writer.h5
-rw-r--r--compiler/debug/elf_debug_writer.cc40
-rw-r--r--compiler/debug/elf_debug_writer.h7
-rw-r--r--compiler/debug/elf_gnu_debugdata_writer.h10
-rw-r--r--compiler/debug/elf_symtab_writer.h5
-rw-r--r--compiler/dex/dex_to_dex_compiler.cc1
-rw-r--r--compiler/driver/compiler_driver-inl.h18
-rw-r--r--compiler/driver/compiler_driver.cc20
-rw-r--r--compiler/driver/compiler_driver.h24
-rw-r--r--compiler/linker/elf_builder.h224
-rw-r--r--compiler/optimizing/inliner.cc4
-rw-r--r--compiler/optimizing/instruction_builder.cc18
-rw-r--r--compiler/optimizing/instruction_simplifier.cc21
-rw-r--r--compiler/optimizing/nodes.cc14
-rw-r--r--compiler/optimizing/nodes.h16
-rw-r--r--compiler/optimizing/nodes_vector.h10
-rw-r--r--compiler/optimizing/optimizing_compiler.cc18
-rw-r--r--compiler/optimizing/reference_type_propagation.cc6
-rw-r--r--compiler/optimizing/scheduler.h5
-rw-r--r--compiler/optimizing/scheduler_arm64.h14
-rw-r--r--compiler/verifier_deps_test.cc3
-rw-r--r--dex2oat/dex2oat.cc2
-rw-r--r--dex2oat/linker/elf_writer_quick.cc6
-rw-r--r--dex2oat/linker/image_writer.cc8
-rw-r--r--dex2oat/linker/oat_writer.cc8
-rw-r--r--dexdump/dexdump.cc12
-rw-r--r--dexlist/dexlist.cc2
-rw-r--r--oatdump/oatdump.cc13
-rw-r--r--openjdkjvmti/ti_ddms.cc24
-rw-r--r--openjdkjvmti/ti_extension.cc2
-rw-r--r--openjdkjvmti/ti_method.cc44
-rw-r--r--runtime/art_field-inl.h26
-rw-r--r--runtime/art_method-inl.h25
-rw-r--r--runtime/base/macros.h4
-rw-r--r--runtime/cdex/compact_dex_level.h16
-rw-r--r--runtime/check_jni.cc4
-rw-r--r--runtime/class_linker-inl.h120
-rw-r--r--runtime/class_linker.cc143
-rw-r--r--runtime/class_linker.h87
-rw-r--r--runtime/class_linker_test.cc20
-rw-r--r--runtime/code_item_accessors-inl.h28
-rw-r--r--runtime/code_item_accessors.h24
-rw-r--r--runtime/debugger.cc64
-rw-r--r--runtime/dex_file-inl.h21
-rw-r--r--runtime/dex_file.h7
-rw-r--r--runtime/dex_file_annotations.cc18
-rw-r--r--runtime/dex_file_test.cc9
-rw-r--r--runtime/entrypoints/entrypoint_utils-inl.h2
-rw-r--r--runtime/entrypoints/quick/quick_trampoline_entrypoints.cc14
-rw-r--r--runtime/gc/space/image_space.cc4
-rw-r--r--runtime/interpreter/interpreter_common.cc3
-rw-r--r--runtime/jit/jit.cc4
-rw-r--r--runtime/jni_internal_test.cc145
-rw-r--r--runtime/mirror/class-inl.h2
-rw-r--r--runtime/mirror/class.cc6
-rw-r--r--runtime/native/dalvik_system_VMRuntime.cc8
-rw-r--r--runtime/native/java_lang_Class.cc4
-rw-r--r--runtime/runtime.cc1
-rw-r--r--runtime/verifier/method_verifier.cc19
-rw-r--r--test/004-JniTest/expected.txt1
-rw-r--r--test/004-JniTest/jni_test.cc8
-rw-r--r--test/004-JniTest/src/Main.java15
-rwxr-xr-xtest/137-cfi/run7
-rwxr-xr-xtest/1940-ddms-ext/check21
-rw-r--r--test/1940-ddms-ext/expected.txt11
-rw-r--r--test/1940-ddms-ext/src-art/art/Test1940.java58
-rw-r--r--test/458-checker-instruct-simplification/src/Main.java138
-rw-r--r--test/667-jit-jni-stub/src/Main.java9
-rw-r--r--test/706-checker-scheduler/src/Main.java64
-rw-r--r--test/AllFields/AllFields.java2
-rw-r--r--test/AllFields/AllFieldsSub.java17
-rw-r--r--test/AllFields/AllFieldsUnrelated.java17
-rw-r--r--tools/external_oj_libjdwp_art_failures.txt (renamed from tools/libjdwp_oj_art_failures.txt)12
-rw-r--r--tools/jfuzz/README.md14
-rwxr-xr-xtools/jfuzz/run_dex_fuzz_test.py30
-rwxr-xr-xtools/jfuzz/run_jfuzz_test.py97
-rw-r--r--tools/prebuilt_libjdwp_art_failures.txt (renamed from tools/libjdwp_art_failures.txt)6
-rwxr-xr-xtools/run-libjdwp-tests.sh2
-rwxr-xr-xtools/run-prebuilt-libjdwp-tests.sh2
84 files changed, 1302 insertions, 724 deletions
diff --git a/build/Android.common_build.mk b/build/Android.common_build.mk
index f5a95fa0cf..08962526dd 100644
--- a/build/Android.common_build.mk
+++ b/build/Android.common_build.mk
@@ -49,6 +49,11 @@ endif
# Enable the read barrier by default.
ART_USE_READ_BARRIER ?= true
+# Default compact dex level to none.
+ifeq ($(ART_DEFAULT_COMPACT_DEX_LEVEL),)
+ART_DEFAULT_COMPACT_DEX_LEVEL := none
+endif
+
ART_CPP_EXTENSION := .cc
ifndef LIBART_IMG_HOST_BASE_ADDRESS
diff --git a/build/art.go b/build/art.go
index 5704b43834..3f598da00a 100644
--- a/build/art.go
+++ b/build/art.go
@@ -66,6 +66,9 @@ func globalFlags(ctx android.BaseContext) ([]string, []string) {
"-DART_READ_BARRIER_TYPE_IS_"+barrierType+"=1")
}
+ cdexLevel := envDefault(ctx, "ART_DEFAULT_COMPACT_DEX_LEVEL", "none")
+ cflags = append(cflags, "-DART_DEFAULT_COMPACT_DEX_LEVEL="+cdexLevel)
+
// We need larger stack overflow guards for ASAN, as the compiled code will have
// larger frame sizes. For simplicity, just use global not-target-specific cflags.
// Note: We increase this for both debug and non-debug, as the overflow gap will
diff --git a/compiler/debug/elf_debug_frame_writer.h b/compiler/debug/elf_debug_frame_writer.h
index d0c98a7b79..27b70c8caa 100644
--- a/compiler/debug/elf_debug_frame_writer.h
+++ b/compiler/debug/elf_debug_frame_writer.h
@@ -207,13 +207,12 @@ void WriteCFISection(linker::ElfBuilder<ElfTypes>* builder,
}
// Write .eh_frame/.debug_frame section.
- auto* cfi_section = (format == dwarf::DW_DEBUG_FRAME_FORMAT
- ? builder->GetDebugFrame()
- : builder->GetEhFrame());
+ const bool is_debug_frame = format == dwarf::DW_DEBUG_FRAME_FORMAT;
+ auto* cfi_section = (is_debug_frame ? builder->GetDebugFrame() : builder->GetEhFrame());
{
cfi_section->Start();
const bool is64bit = Is64BitInstructionSet(builder->GetIsa());
- const Elf_Addr cfi_address = cfi_section->GetAddress();
+ const Elf_Addr cfi_address = (is_debug_frame ? 0 : cfi_section->GetAddress());
const Elf_Addr cie_address = cfi_address;
Elf_Addr buffer_address = cfi_address;
std::vector<uint8_t> buffer; // Small temporary buffer.
diff --git a/compiler/debug/elf_debug_info_writer.h b/compiler/debug/elf_debug_info_writer.h
index d5999941d7..107ed488cd 100644
--- a/compiler/debug/elf_debug_info_writer.h
+++ b/compiler/debug/elf_debug_info_writer.h
@@ -22,6 +22,7 @@
#include <vector>
#include "art_field-inl.h"
+#include "code_item_accessors-inl.h"
#include "debug/dwarf/debug_abbrev_writer.h"
#include "debug/dwarf/debug_info_entry_writer.h"
#include "debug/elf_compilation_unit.h"
@@ -48,10 +49,10 @@ static void LocalInfoCallback(void* ctx, const DexFile::LocalInfo& entry) {
static std::vector<const char*> GetParamNames(const MethodDebugInfo* mi) {
std::vector<const char*> names;
- if (mi->code_item != nullptr) {
+ CodeItemDebugInfoAccessor accessor(mi->dex_file, mi->code_item);
+ if (accessor.HasCodeItem()) {
DCHECK(mi->dex_file != nullptr);
- uint32_t debug_info_offset = OatFile::GetDebugInfoOffset(*mi->dex_file, mi->code_item);
- const uint8_t* stream = mi->dex_file->GetDebugInfoStream(debug_info_offset);
+ const uint8_t* stream = mi->dex_file->GetDebugInfoStream(accessor.DebugInfoOffset());
if (stream != nullptr) {
DecodeUnsignedLeb128(&stream); // line.
uint32_t parameters_size = DecodeUnsignedLeb128(&stream);
@@ -162,7 +163,7 @@ class ElfCompilationUnitWriter {
for (auto mi : compilation_unit.methods) {
DCHECK(mi->dex_file != nullptr);
const DexFile* dex = mi->dex_file;
- const DexFile::CodeItem* dex_code = mi->code_item;
+ CodeItemDebugInfoAccessor accessor(dex, mi->code_item);
const DexFile::MethodId& dex_method = dex->GetMethodId(mi->dex_method_index);
const DexFile::ProtoId& dex_proto = dex->GetMethodPrototype(dex_method);
const DexFile::TypeList* dex_params = dex->GetProtoParameters(dex_proto);
@@ -204,13 +205,13 @@ class ElfCompilationUnitWriter {
// Decode dex register locations for all stack maps.
// It might be expensive, so do it just once and reuse the result.
std::vector<DexRegisterMap> dex_reg_maps;
- if (dex_code != nullptr && mi->code_info != nullptr) {
+ if (accessor.HasCodeItem() && mi->code_info != nullptr) {
const CodeInfo code_info(mi->code_info);
CodeInfoEncoding encoding = code_info.ExtractEncoding();
for (size_t s = 0; s < code_info.GetNumberOfStackMaps(encoding); ++s) {
const StackMap& stack_map = code_info.GetStackMapAt(s, encoding);
dex_reg_maps.push_back(code_info.GetDexRegisterMapOf(
- stack_map, encoding, dex_code->registers_size_));
+ stack_map, encoding, accessor.RegistersSize()));
}
}
@@ -224,9 +225,9 @@ class ElfCompilationUnitWriter {
WriteName("this");
info_.WriteFlagPresent(DW_AT_artificial);
WriteLazyType(dex_class_desc);
- if (dex_code != nullptr) {
+ if (accessor.HasCodeItem()) {
// Write the stack location of the parameter.
- const uint32_t vreg = dex_code->registers_size_ - dex_code->ins_size_ + arg_reg;
+ const uint32_t vreg = accessor.RegistersSize() - accessor.InsSize() + arg_reg;
const bool is64bitValue = false;
WriteRegLocation(mi, dex_reg_maps, vreg, is64bitValue, compilation_unit.code_address);
}
@@ -244,30 +245,31 @@ class ElfCompilationUnitWriter {
const char* type_desc = dex->StringByTypeIdx(dex_params->GetTypeItem(i).type_idx_);
WriteLazyType(type_desc);
const bool is64bitValue = type_desc[0] == 'D' || type_desc[0] == 'J';
- if (dex_code != nullptr) {
+ if (accessor.HasCodeItem()) {
// Write the stack location of the parameter.
- const uint32_t vreg = dex_code->registers_size_ - dex_code->ins_size_ + arg_reg;
+ const uint32_t vreg = accessor.RegistersSize() - accessor.InsSize() + arg_reg;
WriteRegLocation(mi, dex_reg_maps, vreg, is64bitValue, compilation_unit.code_address);
}
arg_reg += is64bitValue ? 2 : 1;
info_.EndTag();
}
- if (dex_code != nullptr) {
- DCHECK_EQ(arg_reg, dex_code->ins_size_);
+ if (accessor.HasCodeItem()) {
+ DCHECK_EQ(arg_reg, accessor.InsSize());
}
}
// Write local variables.
LocalInfos local_infos;
- uint32_t debug_info_offset = OatFile::GetDebugInfoOffset(*dex, dex_code);
- if (dex->DecodeDebugLocalInfo(dex_code,
- debug_info_offset,
+ if (dex->DecodeDebugLocalInfo(accessor.RegistersSize(),
+ accessor.InsSize(),
+ accessor.InsnsSizeInCodeUnits(),
+ accessor.DebugInfoOffset(),
is_static,
mi->dex_method_index,
LocalInfoCallback,
&local_infos)) {
for (const DexFile::LocalInfo& var : local_infos) {
- if (var.reg_ < dex_code->registers_size_ - dex_code->ins_size_) {
+ if (var.reg_ < accessor.RegistersSize() - accessor.InsSize()) {
info_.StartTag(DW_TAG_variable);
WriteName(var.name_);
WriteLazyType(var.descriptor_);
@@ -296,7 +298,7 @@ class ElfCompilationUnitWriter {
CHECK_EQ(info_.Depth(), 0);
std::vector<uint8_t> buffer;
buffer.reserve(info_.data()->size() + KB);
- const size_t offset = owner_->builder_->GetDebugInfo()->GetSize();
+ const size_t offset = owner_->builder_->GetDebugInfo()->GetPosition();
// All compilation units share single table which is at the start of .debug_abbrev.
const size_t debug_abbrev_offset = 0;
WriteDebugInfoCU(debug_abbrev_offset, info_, offset, &buffer, &owner_->debug_info_patches_);
@@ -461,7 +463,7 @@ class ElfCompilationUnitWriter {
CHECK_EQ(info_.Depth(), 0);
std::vector<uint8_t> buffer;
buffer.reserve(info_.data()->size() + KB);
- const size_t offset = owner_->builder_->GetDebugInfo()->GetSize();
+ const size_t offset = owner_->builder_->GetDebugInfo()->GetPosition();
// All compilation units share single table which is at the start of .debug_abbrev.
const size_t debug_abbrev_offset = 0;
WriteDebugInfoCU(debug_abbrev_offset, info_, offset, &buffer, &owner_->debug_info_patches_);
diff --git a/compiler/debug/elf_debug_line_writer.h b/compiler/debug/elf_debug_line_writer.h
index 943e03a765..d7fd52448c 100644
--- a/compiler/debug/elf_debug_line_writer.h
+++ b/compiler/debug/elf_debug_line_writer.h
@@ -60,7 +60,7 @@ class ElfDebugLineWriter {
? builder_->GetText()->GetAddress()
: 0;
- compilation_unit.debug_line_offset = builder_->GetDebugLine()->GetSize();
+ compilation_unit.debug_line_offset = builder_->GetDebugLine()->GetPosition();
std::vector<dwarf::FileEntry> files;
std::unordered_map<std::string, size_t> files_map;
@@ -159,9 +159,9 @@ class ElfDebugLineWriter {
PositionInfos dex2line_map;
DCHECK(mi->dex_file != nullptr);
const DexFile* dex = mi->dex_file;
- uint32_t debug_info_offset = OatFile::GetDebugInfoOffset(*dex, mi->code_item);
- if (!dex->DecodeDebugPositionInfo(
- mi->code_item, debug_info_offset, PositionInfoCallback, &dex2line_map)) {
+ CodeItemDebugInfoAccessor accessor(dex, mi->code_item);
+ const uint32_t debug_info_offset = accessor.DebugInfoOffset();
+ if (!dex->DecodeDebugPositionInfo(debug_info_offset, PositionInfoCallback, &dex2line_map)) {
continue;
}
@@ -268,7 +268,7 @@ class ElfDebugLineWriter {
}
std::vector<uint8_t> buffer;
buffer.reserve(opcodes.data()->size() + KB);
- size_t offset = builder_->GetDebugLine()->GetSize();
+ size_t offset = builder_->GetDebugLine()->GetPosition();
WriteDebugLineTable(directories, files, opcodes, offset, &buffer, &debug_line_patches_);
builder_->GetDebugLine()->WriteFully(buffer.data(), buffer.size());
return buffer.size();
diff --git a/compiler/debug/elf_debug_loc_writer.h b/compiler/debug/elf_debug_loc_writer.h
index bb856b29f4..1d609af4e6 100644
--- a/compiler/debug/elf_debug_loc_writer.h
+++ b/compiler/debug/elf_debug_loc_writer.h
@@ -251,7 +251,10 @@ static void WriteDebugLocEntry(const MethodDebugInfo* method_info,
// kInStackLargeOffset and kConstantLargeValue are hidden by GetKind().
// kInRegisterHigh and kInFpuRegisterHigh should be handled by
// the special cases above and they should not occur alone.
- LOG(ERROR) << "Unexpected register location kind: " << kind;
+ LOG(WARNING) << "Unexpected register location: " << kind
+ << " (This can indicate either a bug in the dexer when generating"
+ << " local variable information, or a bug in ART compiler."
+ << " Please file a bug at go/art-bug)";
break;
}
if (is64bitValue) {
diff --git a/compiler/debug/elf_debug_writer.cc b/compiler/debug/elf_debug_writer.cc
index 33c46d7e1f..a6267292bf 100644
--- a/compiler/debug/elf_debug_writer.cc
+++ b/compiler/debug/elf_debug_writer.cc
@@ -108,29 +108,32 @@ void WriteDebugInfo(linker::ElfBuilder<ElfTypes>* builder,
std::vector<uint8_t> MakeMiniDebugInfo(
InstructionSet isa,
const InstructionSetFeatures* features,
- size_t rodata_size,
+ uint64_t text_address,
size_t text_size,
const ArrayRef<const MethodDebugInfo>& method_infos) {
if (Is64BitInstructionSet(isa)) {
return MakeMiniDebugInfoInternal<ElfTypes64>(isa,
features,
- rodata_size,
+ text_address,
text_size,
method_infos);
} else {
return MakeMiniDebugInfoInternal<ElfTypes32>(isa,
features,
- rodata_size,
+ text_address,
text_size,
method_infos);
}
}
template <typename ElfTypes>
-static std::vector<uint8_t> WriteDebugElfFileForMethodsInternal(
+static std::vector<uint8_t> MakeElfFileForJITInternal(
InstructionSet isa,
const InstructionSetFeatures* features,
- const ArrayRef<const MethodDebugInfo>& method_infos) {
+ bool mini_debug_info,
+ const MethodDebugInfo& mi) {
+ CHECK_EQ(mi.is_code_address_text_relative, false);
+ ArrayRef<const MethodDebugInfo> method_infos(&mi, 1);
std::vector<uint8_t> buffer;
buffer.reserve(KB);
linker::VectorOutputStream out("Debug ELF file", &buffer);
@@ -138,23 +141,34 @@ static std::vector<uint8_t> WriteDebugElfFileForMethodsInternal(
new linker::ElfBuilder<ElfTypes>(isa, features, &out));
// No program headers since the ELF file is not linked and has no allocated sections.
builder->Start(false /* write_program_headers */);
- WriteDebugInfo(builder.get(),
- method_infos,
- dwarf::DW_DEBUG_FRAME_FORMAT,
- false /* write_oat_patches */);
+ if (mini_debug_info) {
+ std::vector<uint8_t> mdi = MakeMiniDebugInfo(isa,
+ features,
+ mi.code_address,
+ mi.code_size,
+ method_infos);
+ builder->WriteSection(".gnu_debugdata", &mdi);
+ } else {
+ builder->GetText()->AllocateVirtualMemory(mi.code_address, mi.code_size);
+ WriteDebugInfo(builder.get(),
+ method_infos,
+ dwarf::DW_DEBUG_FRAME_FORMAT,
+ false /* write_oat_patches */);
+ }
builder->End();
CHECK(builder->Good());
return buffer;
}
-std::vector<uint8_t> WriteDebugElfFileForMethods(
+std::vector<uint8_t> MakeElfFileForJIT(
InstructionSet isa,
const InstructionSetFeatures* features,
- const ArrayRef<const MethodDebugInfo>& method_infos) {
+ bool mini_debug_info,
+ const MethodDebugInfo& method_info) {
if (Is64BitInstructionSet(isa)) {
- return WriteDebugElfFileForMethodsInternal<ElfTypes64>(isa, features, method_infos);
+ return MakeElfFileForJITInternal<ElfTypes64>(isa, features, mini_debug_info, method_info);
} else {
- return WriteDebugElfFileForMethodsInternal<ElfTypes32>(isa, features, method_infos);
+ return MakeElfFileForJITInternal<ElfTypes32>(isa, features, mini_debug_info, method_info);
}
}
diff --git a/compiler/debug/elf_debug_writer.h b/compiler/debug/elf_debug_writer.h
index d24ca9b203..a47bf076b9 100644
--- a/compiler/debug/elf_debug_writer.h
+++ b/compiler/debug/elf_debug_writer.h
@@ -43,14 +43,15 @@ void WriteDebugInfo(
std::vector<uint8_t> MakeMiniDebugInfo(
InstructionSet isa,
const InstructionSetFeatures* features,
- size_t rodata_section_size,
+ uint64_t text_section_address,
size_t text_section_size,
const ArrayRef<const MethodDebugInfo>& method_infos);
-std::vector<uint8_t> WriteDebugElfFileForMethods(
+std::vector<uint8_t> MakeElfFileForJIT(
InstructionSet isa,
const InstructionSetFeatures* features,
- const ArrayRef<const MethodDebugInfo>& method_infos);
+ bool mini_debug_info,
+ const MethodDebugInfo& method_info);
std::vector<uint8_t> WriteDebugElfFileForClasses(
InstructionSet isa,
diff --git a/compiler/debug/elf_gnu_debugdata_writer.h b/compiler/debug/elf_gnu_debugdata_writer.h
index 1cdf6b0ad1..78b8e2780c 100644
--- a/compiler/debug/elf_gnu_debugdata_writer.h
+++ b/compiler/debug/elf_gnu_debugdata_writer.h
@@ -80,7 +80,7 @@ template <typename ElfTypes>
static std::vector<uint8_t> MakeMiniDebugInfoInternal(
InstructionSet isa,
const InstructionSetFeatures* features,
- size_t rodata_section_size,
+ typename ElfTypes::Addr text_section_address,
size_t text_section_size,
const ArrayRef<const MethodDebugInfo>& method_infos) {
std::vector<uint8_t> buffer;
@@ -88,11 +88,9 @@ static std::vector<uint8_t> MakeMiniDebugInfoInternal(
linker::VectorOutputStream out("Mini-debug-info ELF file", &buffer);
std::unique_ptr<linker::ElfBuilder<ElfTypes>> builder(
new linker::ElfBuilder<ElfTypes>(isa, features, &out));
- builder->Start();
- // Mirror .rodata and .text as NOBITS sections.
- // It is needed to detected relocations after compression.
- builder->GetRoData()->WriteNoBitsSection(rodata_section_size);
- builder->GetText()->WriteNoBitsSection(text_section_size);
+ builder->Start(false /* write_program_headers */);
+ // Mirror .text as NOBITS section since the added symbols will reference it.
+ builder->GetText()->AllocateVirtualMemory(text_section_address, text_section_size);
WriteDebugSymbols(builder.get(), method_infos, false /* with_signature */);
WriteCFISection(builder.get(),
method_infos,
diff --git a/compiler/debug/elf_symtab_writer.h b/compiler/debug/elf_symtab_writer.h
index 0907e102a0..57e010f232 100644
--- a/compiler/debug/elf_symtab_writer.h
+++ b/compiler/debug/elf_symtab_writer.h
@@ -79,8 +79,9 @@ static void WriteDebugSymbols(linker::ElfBuilder<ElfTypes>* builder,
last_name_offset = name_offset;
}
- const auto* text = info.is_code_address_text_relative ? builder->GetText() : nullptr;
- uint64_t address = info.code_address + (text != nullptr ? text->GetAddress() : 0);
+ const auto* text = builder->GetText();
+ uint64_t address = info.code_address;
+ address += info.is_code_address_text_relative ? text->GetAddress() : 0;
// Add in code delta, e.g., thumb bit 0 for Thumb2 code.
address += CompiledMethod::CodeDelta(info.isa);
symtab->Add(name_offset, text, address, info.code_size, STB_GLOBAL, STT_FUNC);
diff --git a/compiler/dex/dex_to_dex_compiler.cc b/compiler/dex/dex_to_dex_compiler.cc
index 476903522e..ead909af9a 100644
--- a/compiler/dex/dex_to_dex_compiler.cc
+++ b/compiler/dex/dex_to_dex_compiler.cc
@@ -296,7 +296,6 @@ void DexCompiler::CompileInvokeVirtual(Instruction* inst, uint32_t dex_pc,
ClassLinker* class_linker = unit_.GetClassLinker();
ArtMethod* resolved_method =
class_linker->ResolveMethod<ClassLinker::ResolveMode::kCheckICCEAndIAE>(
- GetDexFile(),
method_idx,
unit_.GetDexCache(),
unit_.GetClassLoader(),
diff --git a/compiler/driver/compiler_driver-inl.h b/compiler/driver/compiler_driver-inl.h
index 42fc4aa5ba..294072d7e7 100644
--- a/compiler/driver/compiler_driver-inl.h
+++ b/compiler/driver/compiler_driver-inl.h
@@ -33,13 +33,15 @@
namespace art {
inline ObjPtr<mirror::Class> CompilerDriver::ResolveClass(
- const ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
- Handle<mirror::ClassLoader> class_loader, dex::TypeIndex cls_index,
+ const ScopedObjectAccess& soa,
+ Handle<mirror::DexCache> dex_cache,
+ Handle<mirror::ClassLoader> class_loader,
+ dex::TypeIndex cls_index,
const DexCompilationUnit* mUnit) {
DCHECK_EQ(dex_cache->GetDexFile(), mUnit->GetDexFile());
DCHECK_EQ(class_loader.Get(), mUnit->GetClassLoader().Get());
- ObjPtr<mirror::Class> cls = mUnit->GetClassLinker()->ResolveType(
- *mUnit->GetDexFile(), cls_index, dex_cache, class_loader);
+ ObjPtr<mirror::Class> cls =
+ mUnit->GetClassLinker()->ResolveType(cls_index, dex_cache, class_loader);
DCHECK_EQ(cls == nullptr, soa.Self()->IsExceptionPending());
if (UNLIKELY(cls == nullptr)) {
// Clean up any exception left by type resolution.
@@ -49,8 +51,10 @@ inline ObjPtr<mirror::Class> CompilerDriver::ResolveClass(
}
inline ObjPtr<mirror::Class> CompilerDriver::ResolveCompilingMethodsClass(
- const ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
- Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit) {
+ const ScopedObjectAccess& soa,
+ Handle<mirror::DexCache> dex_cache,
+ Handle<mirror::ClassLoader> class_loader,
+ const DexCompilationUnit* mUnit) {
DCHECK_EQ(dex_cache->GetDexFile(), mUnit->GetDexFile());
DCHECK_EQ(class_loader.Get(), mUnit->GetClassLoader().Get());
const DexFile::MethodId& referrer_method_id =
@@ -105,7 +109,7 @@ inline ArtMethod* CompilerDriver::ResolveMethod(
DCHECK_EQ(class_loader.Get(), mUnit->GetClassLoader().Get());
ArtMethod* resolved_method =
mUnit->GetClassLinker()->ResolveMethod<ClassLinker::ResolveMode::kCheckICCEAndIAE>(
- *dex_cache->GetDexFile(), method_idx, dex_cache, class_loader, nullptr, invoke_type);
+ method_idx, dex_cache, class_loader, /* referrer */ nullptr, invoke_type);
if (UNLIKELY(resolved_method == nullptr)) {
DCHECK(soa.Self()->IsExceptionPending());
// Clean up any exception left by type resolution.
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index fcc6b8be9e..0631c0f12c 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -1048,22 +1048,21 @@ void CompilerDriver::LoadImageClasses(TimingLogger* timings) {
for (const auto& exception_type : unresolved_exception_types) {
dex::TypeIndex exception_type_idx = exception_type.first;
const DexFile* dex_file = exception_type.second;
- StackHandleScope<2> hs2(self);
+ StackHandleScope<1> hs2(self);
Handle<mirror::DexCache> dex_cache(hs2.NewHandle(class_linker->RegisterDexFile(*dex_file,
nullptr)));
- Handle<mirror::Class> klass(hs2.NewHandle(
+ ObjPtr<mirror::Class> klass =
(dex_cache != nullptr)
- ? class_linker->ResolveType(*dex_file,
- exception_type_idx,
+ ? class_linker->ResolveType(exception_type_idx,
dex_cache,
ScopedNullHandle<mirror::ClassLoader>())
- : nullptr));
+ : nullptr;
if (klass == nullptr) {
const DexFile::TypeId& type_id = dex_file->GetTypeId(exception_type_idx);
const char* descriptor = dex_file->GetTypeDescriptor(type_id);
LOG(FATAL) << "Failed to resolve class " << descriptor;
}
- DCHECK(java_lang_Throwable->IsAssignableFrom(klass.Get()));
+ DCHECK(java_lang_Throwable->IsAssignableFrom(klass));
}
// Resolving exceptions may load classes that reference more exceptions, iterate until no
// more are found
@@ -1638,7 +1637,7 @@ class ResolveClassFieldsAndMethodsVisitor : public CompilationVisitor {
soa.Self(), dex_file)));
// Resolve the class.
ObjPtr<mirror::Class> klass =
- class_linker->ResolveType(dex_file, class_def.class_idx_, dex_cache, class_loader);
+ class_linker->ResolveType(class_def.class_idx_, dex_cache, class_loader);
bool resolve_fields_and_methods;
if (klass == nullptr) {
// Class couldn't be resolved, for example, super-class is in a different dex file. Don't
@@ -1690,7 +1689,10 @@ class ResolveClassFieldsAndMethodsVisitor : public CompilationVisitor {
if (resolve_fields_and_methods) {
while (it.HasNextMethod()) {
ArtMethod* method = class_linker->ResolveMethod<ClassLinker::ResolveMode::kNoChecks>(
- dex_file, it.GetMemberIndex(), dex_cache, class_loader, nullptr,
+ it.GetMemberIndex(),
+ dex_cache,
+ class_loader,
+ /* referrer */ nullptr,
it.GetMethodInvokeType(class_def));
if (method == nullptr) {
CheckAndClearResolveException(soa.Self());
@@ -1726,7 +1728,7 @@ class ResolveTypeVisitor : public CompilationVisitor {
dex_file,
class_loader.Get())));
ObjPtr<mirror::Class> klass = (dex_cache != nullptr)
- ? class_linker->ResolveType(dex_file, dex::TypeIndex(type_idx), dex_cache, class_loader)
+ ? class_linker->ResolveType(dex::TypeIndex(type_idx), dex_cache, class_loader)
: nullptr;
if (klass == nullptr) {
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index ab788e326f..e001726c95 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -219,15 +219,17 @@ class CompilerDriver {
REQUIRES_SHARED(Locks::mutator_lock_);
// Resolve compiling method's class. Returns null on failure.
- ObjPtr<mirror::Class> ResolveCompilingMethodsClass(
- const ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
- Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit)
+ ObjPtr<mirror::Class> ResolveCompilingMethodsClass(const ScopedObjectAccess& soa,
+ Handle<mirror::DexCache> dex_cache,
+ Handle<mirror::ClassLoader> class_loader,
+ const DexCompilationUnit* mUnit)
REQUIRES_SHARED(Locks::mutator_lock_);
- ObjPtr<mirror::Class> ResolveClass(
- const ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
- Handle<mirror::ClassLoader> class_loader, dex::TypeIndex type_index,
- const DexCompilationUnit* mUnit)
+ ObjPtr<mirror::Class> ResolveClass(const ScopedObjectAccess& soa,
+ Handle<mirror::DexCache> dex_cache,
+ Handle<mirror::ClassLoader> class_loader,
+ dex::TypeIndex type_index,
+ const DexCompilationUnit* mUnit)
REQUIRES_SHARED(Locks::mutator_lock_);
// Resolve a field. Returns null on failure, including incompatible class change.
@@ -240,10 +242,10 @@ class CompilerDriver {
REQUIRES_SHARED(Locks::mutator_lock_);
// Can we fast-path an IGET/IPUT access to an instance field? If yes, compute the field offset.
- std::pair<bool, bool> IsFastInstanceField(
- ObjPtr<mirror::DexCache> dex_cache,
- ObjPtr<mirror::Class> referrer_class,
- ArtField* resolved_field, uint16_t field_idx)
+ std::pair<bool, bool> IsFastInstanceField(ObjPtr<mirror::DexCache> dex_cache,
+ ObjPtr<mirror::Class> referrer_class,
+ ArtField* resolved_field,
+ uint16_t field_idx)
REQUIRES_SHARED(Locks::mutator_lock_);
// Resolve a method. Returns null on failure, including incompatible class change.
diff --git a/compiler/linker/elf_builder.h b/compiler/linker/elf_builder.h
index b30b55e9b4..aa3cd98595 100644
--- a/compiler/linker/elf_builder.h
+++ b/compiler/linker/elf_builder.h
@@ -108,8 +108,6 @@ class ElfBuilder FINAL {
section_index_(0),
name_(name),
link_(link),
- started_(false),
- finished_(false),
phdr_flags_(PF_R),
phdr_type_(0) {
DCHECK_GE(align, 1u);
@@ -120,90 +118,62 @@ class ElfBuilder FINAL {
header_.sh_entsize = entsize;
}
- // Start writing of this section.
- void Start() {
- CHECK(!started_);
- CHECK(!finished_);
- started_ = true;
- auto& sections = owner_->sections_;
- // Check that the previous section is complete.
- CHECK(sections.empty() || sections.back()->finished_);
- // The first ELF section index is 1. Index 0 is reserved for NULL.
- section_index_ = sections.size() + 1;
- // Page-align if we switch between allocated and non-allocated sections,
- // or if we change the type of allocation (e.g. executable vs non-executable).
- if (!sections.empty()) {
- if (header_.sh_flags != sections.back()->header_.sh_flags) {
- header_.sh_addralign = kPageSize;
- }
- }
- // Align file position.
- if (header_.sh_type != SHT_NOBITS) {
- header_.sh_offset = owner_->AlignFileOffset(header_.sh_addralign);
- } else {
- header_.sh_offset = 0;
- }
- // Align virtual memory address.
- if ((header_.sh_flags & SHF_ALLOC) != 0) {
- header_.sh_addr = owner_->AlignVirtualAddress(header_.sh_addralign);
- } else {
- header_.sh_addr = 0;
- }
- // Push this section on the list of written sections.
- sections.push_back(this);
+ // Allocate chunk of virtual memory for this section from the owning ElfBuilder.
+ // This must be done at the start for all SHF_ALLOC sections (i.e. mmaped by linker).
+ // It is fine to allocate section but never call Start/End() (e.g. the .bss section).
+ void AllocateVirtualMemory(Elf_Word size) {
+ AllocateVirtualMemory(owner_->virtual_address_, size);
}
- // Finish writing of this section.
- void End() {
- CHECK(started_);
- CHECK(!finished_);
- finished_ = true;
- if (header_.sh_type == SHT_NOBITS) {
- CHECK_GT(header_.sh_size, 0u);
- } else {
- // Use the current file position to determine section size.
- off_t file_offset = owner_->stream_.Seek(0, kSeekCurrent);
- CHECK_GE(file_offset, (off_t)header_.sh_offset);
- header_.sh_size = file_offset - header_.sh_offset;
- }
- if ((header_.sh_flags & SHF_ALLOC) != 0) {
- owner_->virtual_address_ += header_.sh_size;
- }
+ void AllocateVirtualMemory(Elf_Addr addr, Elf_Word size) {
+ CHECK_NE(header_.sh_flags & SHF_ALLOC, 0u);
+ Elf_Word align = AddSection();
+ CHECK_EQ(header_.sh_addr, 0u);
+ header_.sh_addr = RoundUp(addr, align);
+ CHECK(header_.sh_size == 0u || header_.sh_size == size);
+ header_.sh_size = size;
+ CHECK_LE(owner_->virtual_address_, header_.sh_addr);
+ owner_->virtual_address_ = header_.sh_addr + header_.sh_size;
}
- // Get the location of this section in virtual memory.
- Elf_Addr GetAddress() const {
- CHECK(started_);
- return header_.sh_addr;
+ // Start writing file data of this section.
+ void Start() {
+ CHECK(owner_->current_section_ == nullptr);
+ Elf_Word align = AddSection();
+ CHECK_EQ(header_.sh_offset, 0u);
+ header_.sh_offset = owner_->AlignFileOffset(align);
+ owner_->current_section_ = this;
}
- // Returns the size of the content of this section.
- Elf_Word GetSize() const {
- if (finished_) {
- return header_.sh_size;
- } else {
- CHECK(started_);
- CHECK_NE(header_.sh_type, (Elf_Word)SHT_NOBITS);
- return owner_->stream_.Seek(0, kSeekCurrent) - header_.sh_offset;
- }
+ // Finish writing file data of this section.
+ void End() {
+ CHECK(owner_->current_section_ == this);
+ Elf_Word position = GetPosition();
+ CHECK(header_.sh_size == 0u || header_.sh_size == position);
+ header_.sh_size = position;
+ owner_->current_section_ = nullptr;
+ }
+
+ // Get the number of bytes written so far.
+ // Only valid while writing the section.
+ Elf_Word GetPosition() const {
+ CHECK(owner_->current_section_ == this);
+ off_t file_offset = owner_->stream_.Seek(0, kSeekCurrent);
+ DCHECK_GE(file_offset, (off_t)header_.sh_offset);
+ return file_offset - header_.sh_offset;
}
- // Write this section as "NOBITS" section. (used for the .bss section)
- // This means that the ELF file does not contain the initial data for this section
- // and it will be zero-initialized when the ELF file is loaded in the running program.
- void WriteNoBitsSection(Elf_Word size) {
+ // Get the location of this section in virtual memory.
+ Elf_Addr GetAddress() const {
DCHECK_NE(header_.sh_flags & SHF_ALLOC, 0u);
- header_.sh_type = SHT_NOBITS;
- Start();
- header_.sh_size = size;
- End();
+ DCHECK_NE(header_.sh_addr, 0u);
+ return header_.sh_addr;
}
// This function always succeeds to simplify code.
// Use builder's Good() to check the actual status.
bool WriteFully(const void* buffer, size_t byte_count) OVERRIDE {
- CHECK(started_);
- CHECK(!finished_);
+ CHECK(owner_->current_section_ == this);
return owner_->stream_.WriteFully(buffer, byte_count);
}
@@ -221,19 +191,32 @@ class ElfBuilder FINAL {
}
Elf_Word GetSectionIndex() const {
- DCHECK(started_);
DCHECK_NE(section_index_, 0u);
return section_index_;
}
private:
+ // Add this section to the list of generated ELF sections (if not there already).
+ // It also ensures the alignment is sufficient to generate valid program headers,
+ // since that depends on the previous section. It returns the required alignment.
+ Elf_Word AddSection() {
+ if (section_index_ == 0) {
+ std::vector<Section*>& sections = owner_->sections_;
+ Elf_Word last = sections.empty() ? PF_R : sections.back()->phdr_flags_;
+ if (phdr_flags_ != last) {
+ header_.sh_addralign = kPageSize; // Page-align if R/W/X flags changed.
+ }
+ sections.push_back(this);
+ section_index_ = sections.size(); // First ELF section has index 1.
+ }
+ return owner_->write_program_headers_ ? header_.sh_addralign : 1;
+ }
+
ElfBuilder<ElfTypes>* owner_;
Elf_Shdr header_;
Elf_Word section_index_;
const std::string name_;
const Section* const link_;
- bool started_;
- bool finished_;
Elf_Word phdr_flags_;
Elf_Word phdr_type_;
@@ -370,7 +353,7 @@ class ElfBuilder FINAL {
Elf_Word section_index;
if (section != nullptr) {
DCHECK_LE(section->GetAddress(), addr);
- DCHECK_LE(addr, section->GetAddress() + section->GetSize());
+ DCHECK_LE(addr, section->GetAddress() + section->header_.sh_size);
section_index = section->GetSectionIndex();
} else {
section_index = static_cast<Elf_Word>(SHN_ABS);
@@ -479,6 +462,10 @@ class ElfBuilder FINAL {
digest_start_(-1) {
}
+ Elf_Word GetSize() {
+ return 16 + kBuildIdLen;
+ }
+
void Write() {
// The size fields are 32-bit on both 32-bit and 64-bit systems, confirmed
// with the 64-bit linker and libbfd code. The size of name and desc must
@@ -490,6 +477,7 @@ class ElfBuilder FINAL {
digest_start_ = this->Seek(0, kSeekCurrent);
static_assert(kBuildIdLen % 4 == 0, "expecting a mutliple of 4 for build ID length");
this->WriteFully(std::string(kBuildIdLen, '\0').c_str(), kBuildIdLen); // desc.
+ DCHECK_EQ(this->GetPosition(), GetSize());
}
off_t GetDigestStart() {
@@ -530,6 +518,7 @@ class ElfBuilder FINAL {
abiflags_(this, ".MIPS.abiflags", SHT_MIPS_ABIFLAGS, SHF_ALLOC, nullptr, 0, kPageSize, 0,
isa, features),
build_id_(this, ".note.gnu.build-id", SHT_NOTE, SHF_ALLOC, nullptr, 0, 4, 0),
+ current_section_(nullptr),
started_(false),
write_program_headers_(false),
loaded_size_(0u),
@@ -545,6 +534,7 @@ class ElfBuilder FINAL {
~ElfBuilder() {}
InstructionSet GetIsa() { return isa_; }
+ BuildIdSection* GetBuildId() { return &build_id_; }
Section* GetRoData() { return &rodata_; }
Section* GetText() { return &text_; }
Section* GetBss() { return &bss_; }
@@ -622,6 +612,9 @@ class ElfBuilder FINAL {
if (section->link_ != nullptr) {
section->header_.sh_link = section->link_->GetSectionIndex();
}
+ if (section->header_.sh_offset == 0) {
+ section->header_.sh_type = SHT_NOBITS;
+ }
}
shstrtab_.End();
@@ -680,65 +673,57 @@ class ElfBuilder FINAL {
soname = soname.substr(directory_separator_pos + 1);
}
- // Calculate addresses of .text, .bss and .dynstr.
- DCHECK_EQ(rodata_.header_.sh_addralign, static_cast<Elf_Word>(kPageSize));
- DCHECK_EQ(text_.header_.sh_addralign, static_cast<Elf_Word>(kPageSize));
- DCHECK_EQ(bss_.header_.sh_addralign, static_cast<Elf_Word>(kPageSize));
- DCHECK_EQ(dynstr_.header_.sh_addralign, static_cast<Elf_Word>(kPageSize));
- Elf_Word rodata_address = rodata_.GetAddress();
- Elf_Word text_address = RoundUp(rodata_address + rodata_size, kPageSize);
- Elf_Word bss_address = RoundUp(text_address + text_size, kPageSize);
- Elf_Word abiflags_address = RoundUp(bss_address + bss_size, kPageSize);
- Elf_Word abiflags_size = 0;
+ // Allocate all pre-dynamic sections.
+ rodata_.AllocateVirtualMemory(rodata_size);
+ text_.AllocateVirtualMemory(text_size);
+ if (bss_size != 0) {
+ bss_.AllocateVirtualMemory(bss_size);
+ }
if (isa_ == InstructionSet::kMips || isa_ == InstructionSet::kMips64) {
- abiflags_size = abiflags_.GetSize();
+ abiflags_.AllocateVirtualMemory(abiflags_.GetSize());
}
- Elf_Word dynstr_address = RoundUp(abiflags_address + abiflags_size, kPageSize);
// Cache .dynstr, .dynsym and .hash data.
dynstr_.Add(""); // dynstr should start with empty string.
- Elf_Word rodata_index = rodata_.GetSectionIndex();
Elf_Word oatdata = dynstr_.Add("oatdata");
- dynsym_.Add(oatdata, rodata_index, rodata_address, rodata_size, STB_GLOBAL, STT_OBJECT);
+ dynsym_.Add(oatdata, &rodata_, rodata_.GetAddress(), rodata_size, STB_GLOBAL, STT_OBJECT);
if (text_size != 0u) {
- Elf_Word text_index = rodata_index + 1u;
Elf_Word oatexec = dynstr_.Add("oatexec");
- dynsym_.Add(oatexec, text_index, text_address, text_size, STB_GLOBAL, STT_OBJECT);
+ dynsym_.Add(oatexec, &text_, text_.GetAddress(), text_size, STB_GLOBAL, STT_OBJECT);
Elf_Word oatlastword = dynstr_.Add("oatlastword");
- Elf_Word oatlastword_address = text_address + text_size - 4;
- dynsym_.Add(oatlastword, text_index, oatlastword_address, 4, STB_GLOBAL, STT_OBJECT);
+ Elf_Word oatlastword_address = text_.GetAddress() + text_size - 4;
+ dynsym_.Add(oatlastword, &text_, oatlastword_address, 4, STB_GLOBAL, STT_OBJECT);
} else if (rodata_size != 0) {
// rodata_ can be size 0 for dwarf_test.
Elf_Word oatlastword = dynstr_.Add("oatlastword");
- Elf_Word oatlastword_address = rodata_address + rodata_size - 4;
- dynsym_.Add(oatlastword, rodata_index, oatlastword_address, 4, STB_GLOBAL, STT_OBJECT);
+ Elf_Word oatlastword_address = rodata_.GetAddress() + rodata_size - 4;
+ dynsym_.Add(oatlastword, &rodata_, oatlastword_address, 4, STB_GLOBAL, STT_OBJECT);
}
DCHECK_LE(bss_roots_offset, bss_size);
if (bss_size != 0u) {
- Elf_Word bss_index = rodata_index + 1u + (text_size != 0 ? 1u : 0u);
Elf_Word oatbss = dynstr_.Add("oatbss");
- dynsym_.Add(oatbss, bss_index, bss_address, bss_roots_offset, STB_GLOBAL, STT_OBJECT);
+ dynsym_.Add(oatbss, &bss_, bss_.GetAddress(), bss_roots_offset, STB_GLOBAL, STT_OBJECT);
DCHECK_LE(bss_methods_offset, bss_roots_offset);
DCHECK_LE(bss_roots_offset, bss_size);
// Add a symbol marking the start of the methods part of the .bss, if not empty.
if (bss_methods_offset != bss_roots_offset) {
- Elf_Word bss_methods_address = bss_address + bss_methods_offset;
+ Elf_Word bss_methods_address = bss_.GetAddress() + bss_methods_offset;
Elf_Word bss_methods_size = bss_roots_offset - bss_methods_offset;
Elf_Word oatbssroots = dynstr_.Add("oatbssmethods");
dynsym_.Add(
- oatbssroots, bss_index, bss_methods_address, bss_methods_size, STB_GLOBAL, STT_OBJECT);
+ oatbssroots, &bss_, bss_methods_address, bss_methods_size, STB_GLOBAL, STT_OBJECT);
}
// Add a symbol marking the start of the GC roots part of the .bss, if not empty.
if (bss_roots_offset != bss_size) {
- Elf_Word bss_roots_address = bss_address + bss_roots_offset;
+ Elf_Word bss_roots_address = bss_.GetAddress() + bss_roots_offset;
Elf_Word bss_roots_size = bss_size - bss_roots_offset;
Elf_Word oatbssroots = dynstr_.Add("oatbssroots");
dynsym_.Add(
- oatbssroots, bss_index, bss_roots_address, bss_roots_size, STB_GLOBAL, STT_OBJECT);
+ oatbssroots, &bss_, bss_roots_address, bss_roots_size, STB_GLOBAL, STT_OBJECT);
}
Elf_Word oatbsslastword = dynstr_.Add("oatbsslastword");
- Elf_Word bsslastword_address = bss_address + bss_size - 4;
- dynsym_.Add(oatbsslastword, bss_index, bsslastword_address, 4, STB_GLOBAL, STT_OBJECT);
+ Elf_Word bsslastword_address = bss_.GetAddress() + bss_size - 4;
+ dynsym_.Add(oatbsslastword, &bss_, bsslastword_address, 4, STB_GLOBAL, STT_OBJECT);
}
Elf_Word soname_offset = dynstr_.Add(soname);
@@ -759,28 +744,24 @@ class ElfBuilder FINAL {
hash.push_back(0); // Last symbol terminates the chain.
hash_.Add(hash.data(), hash.size() * sizeof(hash[0]));
- // Calculate addresses of .dynsym, .hash and .dynamic.
- DCHECK_EQ(dynstr_.header_.sh_flags, dynsym_.header_.sh_flags);
- DCHECK_EQ(dynsym_.header_.sh_flags, hash_.header_.sh_flags);
- Elf_Word dynsym_address =
- RoundUp(dynstr_address + dynstr_.GetCacheSize(), dynsym_.header_.sh_addralign);
- Elf_Word hash_address =
- RoundUp(dynsym_address + dynsym_.GetCacheSize(), hash_.header_.sh_addralign);
- DCHECK_EQ(dynamic_.header_.sh_addralign, static_cast<Elf_Word>(kPageSize));
- Elf_Word dynamic_address = RoundUp(hash_address + dynsym_.GetCacheSize(), kPageSize);
+ // Allocate all remaining sections.
+ dynstr_.AllocateVirtualMemory(dynstr_.GetCacheSize());
+ dynsym_.AllocateVirtualMemory(dynsym_.GetCacheSize());
+ hash_.AllocateVirtualMemory(hash_.GetCacheSize());
Elf_Dyn dyns[] = {
- { DT_HASH, { hash_address } },
- { DT_STRTAB, { dynstr_address } },
- { DT_SYMTAB, { dynsym_address } },
+ { DT_HASH, { hash_.GetAddress() } },
+ { DT_STRTAB, { dynstr_.GetAddress() } },
+ { DT_SYMTAB, { dynsym_.GetAddress() } },
{ DT_SYMENT, { sizeof(Elf_Sym) } },
{ DT_STRSZ, { dynstr_.GetCacheSize() } },
{ DT_SONAME, { soname_offset } },
{ DT_NULL, { 0 } },
};
dynamic_.Add(&dyns, sizeof(dyns));
+ dynamic_.AllocateVirtualMemory(dynamic_.GetCacheSize());
- loaded_size_ = RoundUp(dynamic_address + dynamic_.GetCacheSize(), kPageSize);
+ loaded_size_ = RoundUp(virtual_address_, kPageSize);
}
void WriteDynamicSection() {
@@ -788,8 +769,6 @@ class ElfBuilder FINAL {
dynsym_.WriteCachedSection();
hash_.WriteCachedSection();
dynamic_.WriteCachedSection();
-
- CHECK_EQ(loaded_size_, RoundUp(dynamic_.GetAddress() + dynamic_.GetSize(), kPageSize));
}
Elf_Word GetLoadedSize() {
@@ -828,10 +807,6 @@ class ElfBuilder FINAL {
return stream_.Seek(RoundUp(stream_.Seek(0, kSeekCurrent), alignment), kSeekSet);
}
- Elf_Addr AlignVirtualAddress(size_t alignment) {
- return virtual_address_ = RoundUp(virtual_address_, alignment);
- }
-
private:
static Elf_Ehdr MakeElfHeader(InstructionSet isa, const InstructionSetFeatures* features) {
Elf_Ehdr elf_header = Elf_Ehdr();
@@ -902,7 +877,6 @@ class ElfBuilder FINAL {
elf_header.e_ehsize = sizeof(Elf_Ehdr);
elf_header.e_phentsize = sizeof(Elf_Phdr);
elf_header.e_shentsize = sizeof(Elf_Shdr);
- elf_header.e_phoff = sizeof(Elf_Ehdr);
return elf_header;
}
@@ -933,6 +907,7 @@ class ElfBuilder FINAL {
for (auto* section : sections_) {
const Elf_Shdr& shdr = section->header_;
if ((shdr.sh_flags & SHF_ALLOC) != 0 && shdr.sh_size != 0) {
+ DCHECK(shdr.sh_addr != 0u) << "Allocate virtual memory for the section";
// PT_LOAD tells the linker to mmap part of the file.
// The linker can only mmap page-aligned sections.
// Single PT_LOAD may contain several ELF sections.
@@ -1010,6 +985,7 @@ class ElfBuilder FINAL {
// List of used section in the order in which they were written.
std::vector<Section*> sections_;
+ Section* current_section_; // The section which is currently being written.
bool started_;
bool write_program_headers_;
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index a175c21760..8750910fe1 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -294,7 +294,7 @@ static dex::TypeIndex FindClassIndexIn(mirror::Class* cls,
// as there may be different class loaders. So only return the index if it's
// the right class already resolved with the class loader.
if (index.IsValid()) {
- ObjPtr<mirror::Class> resolved = ClassLinker::LookupResolvedType(
+ ObjPtr<mirror::Class> resolved = compilation_unit.GetClassLinker()->LookupResolvedType(
index, compilation_unit.GetDexCache().Get(), compilation_unit.GetClassLoader().Get());
if (resolved != cls) {
index = dex::TypeIndex::Invalid();
@@ -682,7 +682,7 @@ HInliner::InlineCacheType HInliner::ExtractClassesFromOfflineProfile(
<< "is invalid in location" << dex_cache->GetDexFile()->GetLocation();
return kInlineCacheNoData;
}
- ObjPtr<mirror::Class> clazz = ClassLinker::LookupResolvedType(
+ ObjPtr<mirror::Class> clazz = caller_compilation_unit_.GetClassLinker()->LookupResolvedType(
class_ref.type_index,
dex_cache,
caller_compilation_unit_.GetClassLoader().Get());
diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc
index bce4de32d5..e36d91fb05 100644
--- a/compiler/optimizing/instruction_builder.cc
+++ b/compiler/optimizing/instruction_builder.cc
@@ -442,17 +442,15 @@ ArenaBitVector* HInstructionBuilder::FindNativeDebugInfoLocations() {
return false;
}
};
- const uint32_t num_instructions = code_item_->insns_size_in_code_units_;
+ CodeItemDebugInfoAccessor accessor(dex_file_, code_item_);
ArenaBitVector* locations = ArenaBitVector::Create(local_allocator_,
- num_instructions,
+ accessor.InsnsSizeInCodeUnits(),
/* expandable */ false,
kArenaAllocGraphBuilder);
locations->ClearAllBits();
- uint32_t debug_info_offset = OatFile::GetDebugInfoOffset(*dex_file_, code_item_);
- dex_file_->DecodeDebugPositionInfo(code_item_, debug_info_offset, Callback::Position, locations);
+ dex_file_->DecodeDebugPositionInfo(accessor.DebugInfoOffset(), Callback::Position, locations);
// Instruction-specific tweaks.
- IterationRange<DexInstructionIterator> instructions = code_item_->Instructions();
- for (const DexInstructionPcPair& inst : instructions) {
+ for (const DexInstructionPcPair& inst : accessor) {
switch (inst->Opcode()) {
case Instruction::MOVE_EXCEPTION: {
// Stop in native debugger after the exception has been moved.
@@ -461,7 +459,7 @@ ArenaBitVector* HInstructionBuilder::FindNativeDebugInfoLocations() {
locations->ClearBit(inst.DexPc());
DexInstructionIterator next = std::next(DexInstructionIterator(inst));
DCHECK(next.DexPc() != inst.DexPc());
- if (next != instructions.end()) {
+ if (next != accessor.end()) {
locations->SetBit(next.DexPc());
}
break;
@@ -796,7 +794,6 @@ ArtMethod* HInstructionBuilder::ResolveMethod(uint16_t method_idx, InvokeType in
ArtMethod* resolved_method =
class_linker->ResolveMethod<ClassLinker::ResolveMode::kCheckICCEAndIAE>(
- *dex_compilation_unit_->GetDexFile(),
method_idx,
dex_compilation_unit_->GetDexCache(),
class_loader,
@@ -831,7 +828,6 @@ ArtMethod* HInstructionBuilder::ResolveMethod(uint16_t method_idx, InvokeType in
return nullptr;
}
ObjPtr<mirror::Class> referenced_class = class_linker->LookupResolvedType(
- *dex_compilation_unit_->GetDexFile(),
dex_compilation_unit_->GetDexFile()->GetMethodId(method_idx).class_idx_,
dex_compilation_unit_->GetDexCache().Get(),
class_loader.Get());
@@ -1425,7 +1421,7 @@ bool HInstructionBuilder::BuildInstanceFieldAccess(const Instruction& instructio
}
static ObjPtr<mirror::Class> GetClassFrom(CompilerDriver* driver,
- const DexCompilationUnit& compilation_unit) {
+ const DexCompilationUnit& compilation_unit) {
ScopedObjectAccess soa(Thread::Current());
Handle<mirror::ClassLoader> class_loader = compilation_unit.GetClassLoader();
Handle<mirror::DexCache> dex_cache = compilation_unit.GetDexCache();
@@ -2934,7 +2930,7 @@ bool HInstructionBuilder::ProcessDexInstruction(const Instruction& instruction,
ObjPtr<mirror::Class> HInstructionBuilder::LookupResolvedType(
dex::TypeIndex type_index,
const DexCompilationUnit& compilation_unit) const {
- return ClassLinker::LookupResolvedType(
+ return compilation_unit.GetClassLinker()->LookupResolvedType(
type_index, compilation_unit.GetDexCache().Get(), compilation_unit.GetClassLoader().Get());
}
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index a42a85dc1d..53e449bbbe 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -994,6 +994,27 @@ void InstructionSimplifierVisitor::VisitIf(HIf* instruction) {
instruction->GetBlock()->SwapSuccessors();
RecordSimplification();
}
+ HInstruction* input = instruction->InputAt(0);
+
+ // If a condition 'cond' is evaluated in an HIf instruction then in the successors of the
+ // IF_BLOCK we statically know the value of the condition (TRUE in TRUE_SUCC, FALSE in
+ // FALSE_SUCC). Using that we can replace another evaluation (use) EVAL of the same 'cond'
+ // with TRUE value (FALSE value) if every path from the ENTRY_BLOCK to EVAL_BLOCK contains the
+ // edge HIF_BLOCK->TRUE_SUCC (HIF_BLOCK->FALSE_SUCC).
+ if (!input->IsConstant()) {
+ HBasicBlock* true_succ = instruction->IfTrueSuccessor();
+ HBasicBlock* false_succ = instruction->IfFalseSuccessor();
+
+ DCHECK_EQ(true_succ->GetPredecessors().size(), 1u);
+ input->ReplaceUsesDominatedBy(
+ true_succ->GetFirstInstruction(), GetGraph()->GetIntConstant(1), /* strictly */ false);
+ RecordSimplification();
+
+ DCHECK_EQ(false_succ->GetPredecessors().size(), 1u);
+ input->ReplaceUsesDominatedBy(
+ false_succ->GetFirstInstruction(), GetGraph()->GetIntConstant(0), /* strictly */ false);
+ RecordSimplification();
+ }
}
void InstructionSimplifierVisitor::VisitArrayLength(HArrayLength* instruction) {
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index 5f33ed6303..d39c2aded5 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -1111,10 +1111,10 @@ bool HInstructionList::FoundBefore(const HInstruction* instruction1,
return true;
}
-bool HInstruction::StrictlyDominates(HInstruction* other_instruction) const {
+bool HInstruction::Dominates(HInstruction* other_instruction, bool strictly) const {
if (other_instruction == this) {
// An instruction does not strictly dominate itself.
- return false;
+ return !strictly;
}
HBasicBlock* block = GetBlock();
HBasicBlock* other_block = other_instruction->GetBlock();
@@ -1148,6 +1148,10 @@ bool HInstruction::StrictlyDominates(HInstruction* other_instruction) const {
}
}
+bool HInstruction::StrictlyDominates(HInstruction* other_instruction) const {
+ return Dominates(other_instruction, /* strictly */ true);
+}
+
void HInstruction::RemoveEnvironment() {
RemoveEnvironmentUses(this);
environment_ = nullptr;
@@ -1170,14 +1174,16 @@ void HInstruction::ReplaceWith(HInstruction* other) {
DCHECK(env_uses_.empty());
}
-void HInstruction::ReplaceUsesDominatedBy(HInstruction* dominator, HInstruction* replacement) {
+void HInstruction::ReplaceUsesDominatedBy(HInstruction* dominator,
+ HInstruction* replacement,
+ bool strictly) {
const HUseList<HInstruction*>& uses = GetUses();
for (auto it = uses.begin(), end = uses.end(); it != end; /* ++it below */) {
HInstruction* user = it->GetUser();
size_t index = it->GetIndex();
// Increment `it` now because `*it` may disappear thanks to user->ReplaceInput().
++it;
- if (dominator->StrictlyDominates(user)) {
+ if (dominator->Dominates(user, strictly)) {
user->ReplaceInput(replacement, index);
}
}
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 42a9d95b9a..affd54ed72 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -2098,9 +2098,13 @@ class HInstruction : public ArenaObject<kArenaAllocInstruction> {
return IsRemovable() && !HasUses();
}
- // Does this instruction strictly dominate `other_instruction`?
- // Returns false if this instruction and `other_instruction` are the same.
+ // Does this instruction dominate (strictly or in regular sense depending on 'strictly')
+ // `other_instruction`?
+ // Returns '!strictly' if this instruction and `other_instruction` are the same.
// Aborts if this instruction and `other_instruction` are both phis.
+ bool Dominates(HInstruction* other_instruction, bool strictly) const;
+
+ // Return 'Dominates(other_instruction, /*strictly*/ true)'.
bool StrictlyDominates(HInstruction* other_instruction) const;
int GetId() const { return id_; }
@@ -2161,7 +2165,13 @@ class HInstruction : public ArenaObject<kArenaAllocInstruction> {
void SetLocations(LocationSummary* locations) { locations_ = locations; }
void ReplaceWith(HInstruction* instruction);
- void ReplaceUsesDominatedBy(HInstruction* dominator, HInstruction* replacement);
+
+ // Replace all uses of the instruction which are dominated by 'dominator' with 'replacement'.
+ // 'strictly' determines whether strict or regular domination relation should be checked.
+ void ReplaceUsesDominatedBy(HInstruction* dominator,
+ HInstruction* replacement,
+ bool strictly = true);
+
void ReplaceInput(HInstruction* replacement, size_t index);
// This is almost the same as doing `ReplaceWith()`. But in this helper, the
diff --git a/compiler/optimizing/nodes_vector.h b/compiler/optimizing/nodes_vector.h
index 096349fd73..87dff8403b 100644
--- a/compiler/optimizing/nodes_vector.h
+++ b/compiler/optimizing/nodes_vector.h
@@ -109,6 +109,16 @@ class HVecOperation : public HVariableInputSizeInstruction {
// Assumes vector nodes cannot be moved by default. Each concrete implementation
// that can be moved should override this method and return true.
+ //
+ // Note: similar approach is used for instruction scheduling (if it is turned on for the target):
+ // by default HScheduler::IsSchedulable returns false for a particular HVecOperation.
+ // HScheduler${ARCH}::IsSchedulable can be overridden to return true for an instruction (see
+ // scheduler_arm64.h for example) if it is safe to schedule it; in this case one *must* also
+ // look at/update HScheduler${ARCH}::IsSchedulingBarrier for this instruction.
+ //
+ // Note: For newly introduced vector instructions HScheduler${ARCH}::IsSchedulingBarrier must be
+ // altered to return true if the instruction might reside outside the SIMD loop body since SIMD
+ // registers are not kept alive across vector loop boundaries (yet).
bool CanBeMoved() const OVERRIDE { return false; }
// Tests if all data of a vector node (vector length and packed type) is equal.
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index 73c72fc57a..24b1a123ee 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -1224,7 +1224,7 @@ bool OptimizingCompiler::JitCompile(Thread* self,
}
const CompilerOptions& compiler_options = GetCompilerDriver()->GetCompilerOptions();
- if (compiler_options.GetGenerateDebugInfo()) {
+ if (compiler_options.GenerateAnyDebugInfo()) {
const auto* method_header = reinterpret_cast<const OatQuickMethodHeader*>(code);
const uintptr_t code_address = reinterpret_cast<uintptr_t>(method_header->GetCode());
debug::MethodDebugInfo info = {};
@@ -1244,10 +1244,13 @@ bool OptimizingCompiler::JitCompile(Thread* self,
info.frame_size_in_bytes = method_header->GetFrameSizeInBytes();
info.code_info = nullptr;
info.cfi = jni_compiled_method.GetCfi();
- std::vector<uint8_t> elf_file = debug::WriteDebugElfFileForMethods(
+ // If both flags are passed, generate full debug info.
+ const bool mini_debug_info = !compiler_options.GetGenerateDebugInfo();
+ std::vector<uint8_t> elf_file = debug::MakeElfFileForJIT(
GetCompilerDriver()->GetInstructionSet(),
GetCompilerDriver()->GetInstructionSetFeatures(),
- ArrayRef<const debug::MethodDebugInfo>(&info, 1));
+ mini_debug_info,
+ info);
CreateJITCodeEntryForAddress(code_address, std::move(elf_file));
}
@@ -1352,7 +1355,7 @@ bool OptimizingCompiler::JitCompile(Thread* self,
}
const CompilerOptions& compiler_options = GetCompilerDriver()->GetCompilerOptions();
- if (compiler_options.GetGenerateDebugInfo()) {
+ if (compiler_options.GenerateAnyDebugInfo()) {
const auto* method_header = reinterpret_cast<const OatQuickMethodHeader*>(code);
const uintptr_t code_address = reinterpret_cast<uintptr_t>(method_header->GetCode());
debug::MethodDebugInfo info = {};
@@ -1372,10 +1375,13 @@ bool OptimizingCompiler::JitCompile(Thread* self,
info.frame_size_in_bytes = method_header->GetFrameSizeInBytes();
info.code_info = stack_map_size == 0 ? nullptr : stack_map_data;
info.cfi = ArrayRef<const uint8_t>(*codegen->GetAssembler()->cfi().data());
- std::vector<uint8_t> elf_file = debug::WriteDebugElfFileForMethods(
+ // If both flags are passed, generate full debug info.
+ const bool mini_debug_info = !compiler_options.GetGenerateDebugInfo();
+ std::vector<uint8_t> elf_file = debug::MakeElfFileForJIT(
GetCompilerDriver()->GetInstructionSet(),
GetCompilerDriver()->GetInstructionSetFeatures(),
- ArrayRef<const debug::MethodDebugInfo>(&info, 1));
+ mini_debug_info,
+ info);
CreateJITCodeEntryForAddress(code_address, std::move(elf_file));
}
diff --git a/compiler/optimizing/reference_type_propagation.cc b/compiler/optimizing/reference_type_propagation.cc
index d84f14acc0..8bb124e066 100644
--- a/compiler/optimizing/reference_type_propagation.cc
+++ b/compiler/optimizing/reference_type_propagation.cc
@@ -544,7 +544,7 @@ void ReferenceTypePropagation::RTPVisitor::SetClassAsTypeInfo(HInstruction* inst
// the method is from the String class, the null loader is good enough.
Handle<mirror::ClassLoader> loader(hs.NewHandle<mirror::ClassLoader>(nullptr));
ArtMethod* method = cl->ResolveMethod<ClassLinker::ResolveMode::kNoChecks>(
- dex_file, invoke->GetDexMethodIndex(), dex_cache, loader, nullptr, kDirect);
+ invoke->GetDexMethodIndex(), dex_cache, loader, /* referrer */ nullptr, kDirect);
DCHECK(method != nullptr);
mirror::Class* declaring_class = method->GetDeclaringClass();
DCHECK(declaring_class != nullptr);
@@ -576,8 +576,8 @@ void ReferenceTypePropagation::RTPVisitor::UpdateReferenceTypeInfo(HInstruction*
ScopedObjectAccess soa(Thread::Current());
ObjPtr<mirror::DexCache> dex_cache = FindDexCacheWithHint(soa.Self(), dex_file, hint_dex_cache_);
- ObjPtr<mirror::Class> klass =
- ClassLinker::LookupResolvedType(type_idx, dex_cache, class_loader_.Get());
+ ObjPtr<mirror::Class> klass = Runtime::Current()->GetClassLinker()->LookupResolvedType(
+ type_idx, dex_cache, class_loader_.Get());
SetClassAsTypeInfo(instr, klass, is_exact);
}
diff --git a/compiler/optimizing/scheduler.h b/compiler/optimizing/scheduler.h
index bb7c353bc2..dfa077f7de 100644
--- a/compiler/optimizing/scheduler.h
+++ b/compiler/optimizing/scheduler.h
@@ -462,6 +462,11 @@ class HScheduler {
// containing basic block from being scheduled.
// This method is used to restrict scheduling to instructions that we know are
// safe to handle.
+ //
+ // For newly introduced instructions by default HScheduler::IsSchedulable returns false.
+ // HScheduler${ARCH}::IsSchedulable can be overridden to return true for an instruction (see
+ // scheduler_arm64.h for example) if it is safe to schedule it; in this case one *must* also
+ // look at/update HScheduler${ARCH}::IsSchedulingBarrier for this instruction.
virtual bool IsSchedulable(const HInstruction* instruction) const;
bool IsSchedulable(const HBasicBlock* block) const;
diff --git a/compiler/optimizing/scheduler_arm64.h b/compiler/optimizing/scheduler_arm64.h
index 32f161f26a..f71cb5b784 100644
--- a/compiler/optimizing/scheduler_arm64.h
+++ b/compiler/optimizing/scheduler_arm64.h
@@ -151,6 +151,20 @@ class HSchedulerARM64 : public HScheduler {
#undef CASE_INSTRUCTION_KIND
}
+ // Treat as scheduling barriers those vector instructions whose live ranges exceed the vectorized
+ // loop boundaries. This is a workaround for the lack of notion of SIMD register in the compiler;
+ // around a call we have to save/restore all live SIMD&FP registers (only lower 64 bits of
+ // SIMD&FP registers are callee saved) so don't reorder such vector instructions.
+ //
+ // TODO: remove this when a proper support of SIMD registers is introduced to the compiler.
+ bool IsSchedulingBarrier(const HInstruction* instr) const OVERRIDE {
+ return HScheduler::IsSchedulingBarrier(instr) ||
+ instr->IsVecReduce() ||
+ instr->IsVecExtractScalar() ||
+ instr->IsVecSetScalars() ||
+ instr->IsVecReplicateScalar();
+ }
+
private:
SchedulingLatencyVisitorARM64 arm64_latency_visitor_;
DISALLOW_COPY_AND_ASSIGN(HSchedulerARM64);
diff --git a/compiler/verifier_deps_test.cc b/compiler/verifier_deps_test.cc
index 4709fd0e9e..ee1d7c69bc 100644
--- a/compiler/verifier_deps_test.cc
+++ b/compiler/verifier_deps_test.cc
@@ -158,11 +158,10 @@ class VerifierDepsTest : public CommonCompilerTest {
while (it.HasNextDirectMethod()) {
ArtMethod* resolved_method =
class_linker_->ResolveMethod<ClassLinker::ResolveMode::kNoChecks>(
- *primary_dex_file_,
it.GetMemberIndex(),
dex_cache_handle,
class_loader_handle,
- nullptr,
+ /* referrer */ nullptr,
it.GetMethodInvokeType(*class_def));
CHECK(resolved_method != nullptr);
if (method_name == resolved_method->GetName()) {
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index a70e551ec0..7cb04f2aa8 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -2814,7 +2814,7 @@ class Dex2Oat FINAL {
// Dex files we are compiling, does not include the class path dex files.
std::vector<const DexFile*> dex_files_;
std::string no_inline_from_string_;
- CompactDexLevel compact_dex_level_ = CompactDexLevel::kCompactDexLevelNone;
+ CompactDexLevel compact_dex_level_ = kDefaultCompactDexLevel;
std::vector<std::unique_ptr<linker::ElfWriter>> elf_writers_;
std::vector<std::unique_ptr<linker::OatWriter>> oat_writers_;
diff --git a/dex2oat/linker/elf_writer_quick.cc b/dex2oat/linker/elf_writer_quick.cc
index 5fc33ddf8b..aa64b7d59e 100644
--- a/dex2oat/linker/elf_writer_quick.cc
+++ b/dex2oat/linker/elf_writer_quick.cc
@@ -67,7 +67,7 @@ class DebugInfoTask : public Task {
void Run(Thread*) {
result_ = debug::MakeMiniDebugInfo(isa_,
instruction_set_features_,
- rodata_section_size_,
+ kPageSize + rodata_section_size_, // .text address.
text_section_size_,
method_infos_);
}
@@ -173,6 +173,7 @@ template <typename ElfTypes>
void ElfWriterQuick<ElfTypes>::Start() {
builder_->Start();
if (compiler_options_->GetGenerateBuildId()) {
+ builder_->GetBuildId()->AllocateVirtualMemory(builder_->GetBuildId()->GetSize());
builder_->WriteBuildIdSection();
}
}
@@ -225,9 +226,6 @@ void ElfWriterQuick<ElfTypes>::EndText(OutputStream* text) {
template <typename ElfTypes>
void ElfWriterQuick<ElfTypes>::WriteDynamicSection() {
- if (bss_size_ != 0u) {
- builder_->GetBss()->WriteNoBitsSection(bss_size_);
- }
if (builder_->GetIsa() == InstructionSet::kMips ||
builder_->GetIsa() == InstructionSet::kMips64) {
builder_->WriteMIPSabiflagsSection();
diff --git a/dex2oat/linker/image_writer.cc b/dex2oat/linker/image_writer.cc
index f6ceb27b21..738bbf8e9d 100644
--- a/dex2oat/linker/image_writer.cc
+++ b/dex2oat/linker/image_writer.cc
@@ -1050,8 +1050,7 @@ void ImageWriter::PruneAndPreloadDexCache(ObjPtr<mirror::DexCache> dex_cache,
const DexFile::MethodId& method_id = dex_file.GetMethodId(i);
if (method_id.class_idx_ != last_class_idx) {
last_class_idx = method_id.class_idx_;
- last_class = class_linker->LookupResolvedType(
- dex_file, last_class_idx, dex_cache, class_loader);
+ last_class = class_linker->LookupResolvedType(last_class_idx, dex_cache, class_loader);
if (last_class != nullptr && !KeepClass(last_class)) {
last_class = nullptr;
}
@@ -1096,8 +1095,7 @@ void ImageWriter::PruneAndPreloadDexCache(ObjPtr<mirror::DexCache> dex_cache,
const DexFile::FieldId& field_id = dex_file.GetFieldId(i);
if (field_id.class_idx_ != last_class_idx) {
last_class_idx = field_id.class_idx_;
- last_class = class_linker->LookupResolvedType(
- dex_file, last_class_idx, dex_cache, class_loader);
+ last_class = class_linker->LookupResolvedType(last_class_idx, dex_cache, class_loader);
if (last_class != nullptr && !KeepClass(last_class)) {
last_class = nullptr;
}
@@ -1130,7 +1128,7 @@ void ImageWriter::PruneAndPreloadDexCache(ObjPtr<mirror::DexCache> dex_cache,
uint32_t stored_index = pair.index;
ObjPtr<mirror::Class> klass = pair.object.Read();
if (klass == nullptr || i < stored_index) {
- klass = class_linker->LookupResolvedType(dex_file, type_idx, dex_cache, class_loader);
+ klass = class_linker->LookupResolvedType(type_idx, dex_cache, class_loader);
if (klass != nullptr) {
DCHECK_EQ(dex_cache->GetResolvedType(type_idx), klass);
stored_index = i; // For correct clearing below if not keeping the `klass`.
diff --git a/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc
index b163eeb7b7..d4fc59c6c2 100644
--- a/dex2oat/linker/oat_writer.cc
+++ b/dex2oat/linker/oat_writer.cc
@@ -1592,11 +1592,10 @@ class OatWriter::InitImageMethodVisitor : public OatDexMethodVisitor {
ScopedObjectAccessUnchecked soa(self);
StackHandleScope<1> hs(self);
method = class_linker_->ResolveMethod<ClassLinker::ResolveMode::kNoChecks>(
- *dex_file_,
it.GetMemberIndex(),
hs.NewHandle(dex_cache),
ScopedNullHandle<mirror::ClassLoader>(),
- nullptr,
+ /* referrer */ nullptr,
invoke_type);
if (method == nullptr) {
LOG(FATAL_WITHOUT_ABORT) << "Unexpected failure to resolve a method: "
@@ -1957,7 +1956,7 @@ class OatWriter::WriteCodeMethodVisitor : public OrderedMethodVisitor {
DCHECK(writer_->HasImage());
ObjPtr<mirror::DexCache> dex_cache = GetDexCache(patch.TargetTypeDexFile());
ObjPtr<mirror::Class> type =
- ClassLinker::LookupResolvedType(patch.TargetTypeIndex(), dex_cache, class_loader_);
+ class_linker_->LookupResolvedType(patch.TargetTypeIndex(), dex_cache, class_loader_);
CHECK(type != nullptr);
return type;
}
@@ -2697,7 +2696,8 @@ class OatWriter::WriteQuickeningIndicesMethodVisitor {
CompiledMethod* compiled_method =
driver.GetCompiledMethod(MethodReference(dex_file, method_idx));
const DexFile::CodeItem* code_item = class_it.GetMethodCodeItem();
- uint32_t existing_debug_info_offset = OatFile::GetDebugInfoOffset(*dex_file, code_item);
+ CodeItemDebugInfoAccessor accessor(dex_file, code_item);
+ const uint32_t existing_debug_info_offset = accessor.DebugInfoOffset();
// If the existing offset is already out of bounds (and not magic marker 0xFFFFFFFF)
// we will pretend the method has been quickened.
bool existing_offset_out_of_bounds =
diff --git a/dexdump/dexdump.cc b/dexdump/dexdump.cc
index a7af193f0a..527a5b993c 100644
--- a/dexdump/dexdump.cc
+++ b/dexdump/dexdump.cc
@@ -1203,10 +1203,16 @@ static void dumpCode(const DexFile* pDexFile, u4 idx, u4 flags,
bool is_static = (flags & kAccStatic) != 0;
fprintf(gOutFile, " positions : \n");
uint32_t debug_info_offset = pDexFile->GetDebugInfoOffset(pCode);
- pDexFile->DecodeDebugPositionInfo(pCode, debug_info_offset, dumpPositionsCb, nullptr);
+ pDexFile->DecodeDebugPositionInfo(debug_info_offset, dumpPositionsCb, nullptr);
fprintf(gOutFile, " locals : \n");
- pDexFile->DecodeDebugLocalInfo(
- pCode, debug_info_offset, is_static, idx, dumpLocalsCb, nullptr);
+ pDexFile->DecodeDebugLocalInfo(pCode->registers_size_,
+ pCode->ins_size_,
+ pCode->insns_size_in_code_units_,
+ debug_info_offset,
+ is_static,
+ idx,
+ dumpLocalsCb,
+ nullptr);
}
/*
diff --git a/dexlist/dexlist.cc b/dexlist/dexlist.cc
index 630eacba9b..4c13ed6410 100644
--- a/dexlist/dexlist.cc
+++ b/dexlist/dexlist.cc
@@ -122,7 +122,7 @@ static void dumpMethod(const DexFile* pDexFile,
// Find the first line.
int firstLine = -1;
uint32_t debug_info_offset = pDexFile->GetDebugInfoOffset(pCode);
- pDexFile->DecodeDebugPositionInfo(pCode, debug_info_offset, positionsCb, &firstLine);
+ pDexFile->DecodeDebugPositionInfo(debug_info_offset, positionsCb, &firstLine);
// Method signature.
const Signature signature = pDexFile->GetMethodSignature(pMethodId);
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index 1b4485b233..1a1d8cc76e 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -146,13 +146,10 @@ class OatSymbolizer FINAL {
auto* rodata = builder_->GetRoData();
auto* text = builder_->GetText();
- auto* bss = builder_->GetBss();
const uint8_t* rodata_begin = oat_file_->Begin();
const size_t rodata_size = oat_file_->GetOatHeader().GetExecutableOffset();
- if (no_bits_) {
- rodata->WriteNoBitsSection(rodata_size);
- } else {
+ if (!no_bits_) {
rodata->Start();
rodata->WriteFully(rodata_begin, rodata_size);
rodata->End();
@@ -160,18 +157,12 @@ class OatSymbolizer FINAL {
const uint8_t* text_begin = oat_file_->Begin() + rodata_size;
const size_t text_size = oat_file_->End() - text_begin;
- if (no_bits_) {
- text->WriteNoBitsSection(text_size);
- } else {
+ if (!no_bits_) {
text->Start();
text->WriteFully(text_begin, text_size);
text->End();
}
- if (oat_file_->BssSize() != 0) {
- bss->WriteNoBitsSection(oat_file_->BssSize());
- }
-
if (isa == InstructionSet::kMips || isa == InstructionSet::kMips64) {
builder_->WriteMIPSabiflagsSection();
}
diff --git a/openjdkjvmti/ti_ddms.cc b/openjdkjvmti/ti_ddms.cc
index 500a453f78..0b4906d798 100644
--- a/openjdkjvmti/ti_ddms.cc
+++ b/openjdkjvmti/ti_ddms.cc
@@ -49,14 +49,16 @@ jvmtiError DDMSUtil::HandleChunk(jvmtiEnv* env,
/*out*/jint* type_out,
/*out*/jint* data_length_out,
/*out*/jbyte** data_out) {
- constexpr uint32_t kDdmHeaderSize = sizeof(uint32_t) * 2;
- if (env == nullptr || data_in == nullptr || data_out == nullptr || data_length_out == nullptr) {
+ if (env == nullptr || type_out == nullptr || data_out == nullptr || data_length_out == nullptr) {
return ERR(NULL_POINTER);
- } else if (length_in < static_cast<jint>(kDdmHeaderSize)) {
- // need to get type and length at least.
+ } else if (data_in == nullptr && length_in != 0) {
+ // Data-in shouldn't be null if we have data.
return ERR(ILLEGAL_ARGUMENT);
}
+ *data_length_out = 0;
+ *data_out = nullptr;
+
art::Thread* self = art::Thread::Current();
art::ScopedThreadStateChange(self, art::ThreadState::kNative);
@@ -71,13 +73,15 @@ jvmtiError DDMSUtil::HandleChunk(jvmtiEnv* env,
return ERR(INTERNAL);
} else {
jvmtiError error = OK;
- JvmtiUniquePtr<jbyte[]> ret = AllocJvmtiUniquePtr<jbyte[]>(env, out_data.size(), &error);
- if (error != OK) {
- return error;
+ if (!out_data.empty()) {
+ JvmtiUniquePtr<jbyte[]> ret = AllocJvmtiUniquePtr<jbyte[]>(env, out_data.size(), &error);
+ if (error != OK) {
+ return error;
+ }
+ memcpy(ret.get(), out_data.data(), out_data.size());
+ *data_out = ret.release();
+ *data_length_out = static_cast<jint>(out_data.size());
}
- memcpy(ret.get(), out_data.data(), out_data.size());
- *data_out = ret.release();
- *data_length_out = static_cast<jint>(out_data.size());
return OK;
}
}
diff --git a/openjdkjvmti/ti_extension.cc b/openjdkjvmti/ti_extension.cc
index afd0723d0f..79a8cd6304 100644
--- a/openjdkjvmti/ti_extension.cc
+++ b/openjdkjvmti/ti_extension.cc
@@ -216,7 +216,7 @@ jvmtiError ExtensionUtil::GetExtensionFunctions(jvmtiEnv* env,
{
{ "type_in", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false },
{ "length_in", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false },
- { "data_in", JVMTI_KIND_IN_BUF, JVMTI_TYPE_JBYTE, false },
+ { "data_in", JVMTI_KIND_IN_BUF, JVMTI_TYPE_JBYTE, true },
{ "type_out", JVMTI_KIND_OUT, JVMTI_TYPE_JINT, false },
{ "data_len_out", JVMTI_KIND_OUT, JVMTI_TYPE_JINT, false },
{ "data_out", JVMTI_KIND_ALLOC_BUF, JVMTI_TYPE_JBYTE, false }
diff --git a/openjdkjvmti/ti_method.cc b/openjdkjvmti/ti_method.cc
index 448ce41d0f..4444853427 100644
--- a/openjdkjvmti/ti_method.cc
+++ b/openjdkjvmti/ti_method.cc
@@ -37,6 +37,7 @@
#include "art_method-inl.h"
#include "base/enums.h"
#include "base/mutex-inl.h"
+#include "code_item_accessors-inl.h"
#include "dex_file_annotations.h"
#include "dex_file_types.h"
#include "events-inl.h"
@@ -190,12 +191,17 @@ jvmtiError MethodUtil::GetLocalVariableTable(jvmtiEnv* env,
}
art::ScopedObjectAccess soa(art::Thread::Current());
- const art::DexFile* dex_file = art_method->GetDexFile();
- const art::DexFile::CodeItem* code_item = art_method->GetCodeItem();
- // TODO code_item == nullptr means that the method is abstract (or native, but we check that
+
+ const art::DexFile* const dex_file = art_method->GetDexFile();
+ if (dex_file == nullptr) {
+ return ERR(ABSENT_INFORMATION);
+ }
+
+ // TODO HasCodeItem == false means that the method is abstract (or native, but we check that
// earlier). We should check what is returned by the RI in this situation since it's not clear
// what the appropriate return value is from the spec.
- if (dex_file == nullptr || code_item == nullptr) {
+ art::CodeItemDebugInfoAccessor accessor(art_method);
+ if (!accessor.HasCodeItem()) {
return ERR(ABSENT_INFORMATION);
}
@@ -260,9 +266,10 @@ jvmtiError MethodUtil::GetLocalVariableTable(jvmtiEnv* env,
};
LocalVariableContext context(env);
- uint32_t debug_info_offset = art::OatFile::GetDebugInfoOffset(*dex_file, code_item);
- if (!dex_file->DecodeDebugLocalInfo(code_item,
- debug_info_offset,
+ if (!dex_file->DecodeDebugLocalInfo(accessor.RegistersSize(),
+ accessor.InsSize(),
+ accessor.InsnsSizeInCodeUnits(),
+ accessor.DebugInfoOffset(),
art_method->IsStatic(),
art_method->GetDexMethodIndex(),
LocalVariableContext::Callback,
@@ -462,7 +469,7 @@ jvmtiError MethodUtil::GetLineNumberTable(jvmtiEnv* env,
art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
DCHECK(!art_method->IsRuntimeMethod());
- const art::DexFile::CodeItem* code_item;
+ art::CodeItemDebugInfoAccessor accessor;
const art::DexFile* dex_file;
{
art::ScopedObjectAccess soa(art::Thread::Current());
@@ -477,15 +484,14 @@ jvmtiError MethodUtil::GetLineNumberTable(jvmtiEnv* env,
return ERR(NULL_POINTER);
}
- code_item = art_method->GetCodeItem();
+ accessor = art::CodeItemDebugInfoAccessor(art_method);
dex_file = art_method->GetDexFile();
- DCHECK(code_item != nullptr) << art_method->PrettyMethod() << " " << dex_file->GetLocation();
+ DCHECK(accessor.HasCodeItem()) << art_method->PrettyMethod() << " " << dex_file->GetLocation();
}
LineNumberContext context;
- uint32_t debug_info_offset = art::OatFile::GetDebugInfoOffset(*dex_file, code_item);
bool success = dex_file->DecodeDebugPositionInfo(
- code_item, debug_info_offset, CollectLineNumbers, &context);
+ accessor.DebugInfoOffset(), CollectLineNumbers, &context);
if (!success) {
return ERR(ABSENT_INFORMATION);
}
@@ -613,8 +619,11 @@ class CommonLocalVariableClosure : public art::Closure {
/*out*/art::Primitive::Type* type)
REQUIRES(art::Locks::mutator_lock_) {
const art::DexFile* dex_file = method->GetDexFile();
- const art::DexFile::CodeItem* code_item = method->GetCodeItem();
- if (dex_file == nullptr || code_item == nullptr) {
+ if (dex_file == nullptr) {
+ return ERR(OPAQUE_FRAME);
+ }
+ art::CodeItemDebugInfoAccessor accessor(method);
+ if (!accessor.HasCodeItem()) {
return ERR(OPAQUE_FRAME);
}
@@ -653,9 +662,10 @@ class CommonLocalVariableClosure : public art::Closure {
};
GetLocalVariableInfoContext context(slot_, dex_pc, descriptor, type);
- uint32_t debug_info_offset = art::OatFile::GetDebugInfoOffset(*dex_file, code_item);
- if (!dex_file->DecodeDebugLocalInfo(code_item,
- debug_info_offset,
+ if (!dex_file->DecodeDebugLocalInfo(accessor.RegistersSize(),
+ accessor.InsSize(),
+ accessor.InsnsSizeInCodeUnits(),
+ accessor.DebugInfoOffset(),
method->IsStatic(),
method->GetDexMethodIndex(),
GetLocalVariableInfoContext::Callback,
diff --git a/runtime/art_field-inl.h b/runtime/art_field-inl.h
index 941f9e908c..2b18577ed0 100644
--- a/runtime/art_field-inl.h
+++ b/runtime/art_field-inl.h
@@ -307,16 +307,10 @@ inline ObjPtr<mirror::Class> ArtField::LookupResolvedType() {
if (UNLIKELY(declaring_class->IsProxyClass())) {
return ProxyFindSystemClass(GetTypeDescriptor());
}
- ObjPtr<mirror::DexCache> dex_cache = declaring_class->GetDexCache();
- const DexFile* const dex_file = dex_cache->GetDexFile();
- dex::TypeIndex type_idx = dex_file->GetFieldId(field_index).type_idx_;
- ObjPtr<mirror::Class> type = dex_cache->GetResolvedType(type_idx);
- if (UNLIKELY(type == nullptr)) {
- type = Runtime::Current()->GetClassLinker()->LookupResolvedType(
- *dex_file, type_idx, dex_cache, declaring_class->GetClassLoader());
- DCHECK(!Thread::Current()->IsExceptionPending());
- }
- return type.Ptr();
+ ObjPtr<mirror::Class> type = Runtime::Current()->GetClassLinker()->LookupResolvedType(
+ declaring_class->GetDexFile().GetFieldId(field_index).type_idx_, declaring_class);
+ DCHECK(!Thread::Current()->IsExceptionPending());
+ return type;
}
inline ObjPtr<mirror::Class> ArtField::ResolveType() {
@@ -325,15 +319,9 @@ inline ObjPtr<mirror::Class> ArtField::ResolveType() {
if (UNLIKELY(declaring_class->IsProxyClass())) {
return ProxyFindSystemClass(GetTypeDescriptor());
}
- auto* dex_cache = declaring_class->GetDexCache();
- const DexFile* const dex_file = dex_cache->GetDexFile();
- dex::TypeIndex type_idx = dex_file->GetFieldId(field_index).type_idx_;
- ObjPtr<mirror::Class> type = dex_cache->GetResolvedType(type_idx);
- if (UNLIKELY(type == nullptr)) {
- ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- type = class_linker->ResolveType(*dex_file, type_idx, declaring_class);
- DCHECK_EQ(type == nullptr, Thread::Current()->IsExceptionPending());
- }
+ ObjPtr<mirror::Class> type = Runtime::Current()->GetClassLinker()->ResolveType(
+ declaring_class->GetDexFile().GetFieldId(field_index).type_idx_, declaring_class);
+ DCHECK_EQ(type == nullptr, Thread::Current()->IsExceptionPending());
return type;
}
diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h
index 327081f67a..869394c388 100644
--- a/runtime/art_method-inl.h
+++ b/runtime/art_method-inl.h
@@ -106,23 +106,16 @@ inline uint32_t ArtMethod::GetDexMethodIndex() {
inline ObjPtr<mirror::Class> ArtMethod::LookupResolvedClassFromTypeIndex(dex::TypeIndex type_idx) {
ScopedAssertNoThreadSuspension ants(__FUNCTION__);
- ObjPtr<mirror::DexCache> dex_cache = GetDexCache();
- ObjPtr<mirror::Class> type = dex_cache->GetResolvedType(type_idx);
- if (UNLIKELY(type == nullptr)) {
- type = Runtime::Current()->GetClassLinker()->LookupResolvedType(
- *dex_cache->GetDexFile(), type_idx, dex_cache, GetClassLoader());
- }
- return type.Ptr();
+ ObjPtr<mirror::Class> type =
+ Runtime::Current()->GetClassLinker()->LookupResolvedType(type_idx, this);
+ DCHECK(!Thread::Current()->IsExceptionPending());
+ return type;
}
inline ObjPtr<mirror::Class> ArtMethod::ResolveClassFromTypeIndex(dex::TypeIndex type_idx) {
- ObjPtr<mirror::DexCache> dex_cache = GetDexCache();
- ObjPtr<mirror::Class> type = dex_cache->GetResolvedType(type_idx);
- if (UNLIKELY(type == nullptr)) {
- type = Runtime::Current()->GetClassLinker()->ResolveType(type_idx, this);
- CHECK(type != nullptr || Thread::Current()->IsExceptionPending());
- }
- return type.Ptr();
+ ObjPtr<mirror::Class> type = Runtime::Current()->GetClassLinker()->ResolveType(type_idx, this);
+ DCHECK_EQ(type == nullptr, Thread::Current()->IsExceptionPending());
+ return type;
}
inline bool ArtMethod::CheckIncompatibleClassChange(InvokeType type) {
@@ -305,9 +298,7 @@ inline const DexFile::ClassDef& ArtMethod::GetClassDef() {
inline const char* ArtMethod::GetReturnTypeDescriptor() {
DCHECK(!IsProxyMethod());
const DexFile* dex_file = GetDexFile();
- const DexFile::MethodId& method_id = dex_file->GetMethodId(GetDexMethodIndex());
- const DexFile::ProtoId& proto_id = dex_file->GetMethodPrototype(method_id);
- return dex_file->GetTypeDescriptor(dex_file->GetTypeId(proto_id.return_type_idx_));
+ return dex_file->GetTypeDescriptor(dex_file->GetTypeId(GetReturnTypeIndex()));
}
inline Primitive::Type ArtMethod::GetReturnTypePrimitive() {
diff --git a/runtime/base/macros.h b/runtime/base/macros.h
index 6cd7d60253..512e5ce651 100644
--- a/runtime/base/macros.h
+++ b/runtime/base/macros.h
@@ -59,6 +59,10 @@ template<typename T> ART_FRIEND_TEST(test_set_name, individual_test)
#define QUOTE(x) #x
#define STRINGIFY(x) QUOTE(x)
+// Append tokens after evaluating.
+#define APPEND_TOKENS_AFTER_EVAL_2(a, b) a ## b
+#define APPEND_TOKENS_AFTER_EVAL(a, b) APPEND_TOKENS_AFTER_EVAL_2(a, b)
+
#ifndef NDEBUG
#define ALWAYS_INLINE
#else
diff --git a/runtime/cdex/compact_dex_level.h b/runtime/cdex/compact_dex_level.h
index b824462bf0..5aec00195d 100644
--- a/runtime/cdex/compact_dex_level.h
+++ b/runtime/cdex/compact_dex_level.h
@@ -17,6 +17,9 @@
#ifndef ART_RUNTIME_CDEX_COMPACT_DEX_LEVEL_H_
#define ART_RUNTIME_CDEX_COMPACT_DEX_LEVEL_H_
+#include <string>
+
+#include "base/macros.h"
#include "dex_file.h"
namespace art {
@@ -29,6 +32,19 @@ enum class CompactDexLevel {
kCompactDexLevelFast,
};
+#ifndef ART_DEFAULT_COMPACT_DEX_LEVEL
+#error ART_DEFAULT_COMPACT_DEX_LEVEL not specified.
+#else
+#define ART_DEFAULT_COMPACT_DEX_LEVEL_VALUE_fast CompactDexLevel::kCompactDexLevelFast
+#define ART_DEFAULT_COMPACT_DEX_LEVEL_VALUE_none CompactDexLevel::kCompactDexLevelNone
+
+#define ART_DEFAULT_COMPACT_DEX_LEVEL_DEFAULT APPEND_TOKENS_AFTER_EVAL( \
+ ART_DEFAULT_COMPACT_DEX_LEVEL_VALUE_, \
+ ART_DEFAULT_COMPACT_DEX_LEVEL)
+
+static constexpr CompactDexLevel kDefaultCompactDexLevel = ART_DEFAULT_COMPACT_DEX_LEVEL_DEFAULT;
+#endif
+
} // namespace art
#endif // ART_RUNTIME_CDEX_COMPACT_DEX_LEVEL_H_
diff --git a/runtime/check_jni.cc b/runtime/check_jni.cc
index 0b9bf225d4..90f478f5f4 100644
--- a/runtime/check_jni.cc
+++ b/runtime/check_jni.cc
@@ -373,7 +373,7 @@ class ScopedCheck {
if (f == nullptr) {
return false;
}
- if (c != f->GetDeclaringClass()) {
+ if (!f->GetDeclaringClass()->IsAssignableFrom(c)) {
AbortF("static jfieldID %p not valid for class %s", fid,
mirror::Class::PrettyClass(c).c_str());
return false;
@@ -710,7 +710,7 @@ class ScopedCheck {
return false;
}
ObjPtr<mirror::Class> c = o->AsClass();
- if (c != field->GetDeclaringClass()) {
+ if (!field->GetDeclaringClass()->IsAssignableFrom(c)) {
AbortF("attempt to access static field %s with an incompatible class argument of %s: %p",
field->PrettyField().c_str(), mirror::Class::PrettyDescriptor(c).c_str(), fid);
return false;
diff --git a/runtime/class_linker-inl.h b/runtime/class_linker-inl.h
index 2d8d4b41a0..4b317f886f 100644
--- a/runtime/class_linker-inl.h
+++ b/runtime/class_linker-inl.h
@@ -61,16 +61,27 @@ inline mirror::Class* ClassLinker::FindArrayClass(Thread* self,
return array_class.Ptr();
}
-inline ObjPtr<mirror::Class> ClassLinker::LookupResolvedType(
- dex::TypeIndex type_idx,
- ObjPtr<mirror::DexCache> dex_cache,
- ObjPtr<mirror::ClassLoader> class_loader) {
- ObjPtr<mirror::Class> type = dex_cache->GetResolvedType(type_idx);
- if (type == nullptr) {
- type = Runtime::Current()->GetClassLinker()->LookupResolvedType(
- *dex_cache->GetDexFile(), type_idx, dex_cache, class_loader);
+inline ObjPtr<mirror::Class> ClassLinker::ResolveType(dex::TypeIndex type_idx,
+ ObjPtr<mirror::Class> referrer) {
+ if (kObjPtrPoisoning) {
+ StackHandleScope<1> hs(Thread::Current());
+ HandleWrapperObjPtr<mirror::Class> referrer_wrapper = hs.NewHandleWrapper(&referrer);
+ Thread::Current()->PoisonObjectPointers();
}
- return type;
+ if (kIsDebugBuild) {
+ Thread::Current()->AssertNoPendingException();
+ }
+ // We do not need the read barrier for getting the DexCache for the initial resolved type
+ // lookup as both from-space and to-space copies point to the same native resolved types array.
+ ObjPtr<mirror::Class> resolved_type =
+ referrer->GetDexCache<kDefaultVerifyFlags, kWithoutReadBarrier>()->GetResolvedType(type_idx);
+ if (resolved_type == nullptr) {
+ StackHandleScope<2> hs(Thread::Current());
+ Handle<mirror::DexCache> h_dex_cache(hs.NewHandle(referrer->GetDexCache()));
+ Handle<mirror::ClassLoader> class_loader(hs.NewHandle(referrer->GetClassLoader()));
+ resolved_type = DoResolveType(type_idx, h_dex_cache, class_loader);
+ }
+ return resolved_type;
}
inline ObjPtr<mirror::Class> ClassLinker::ResolveType(dex::TypeIndex type_idx,
@@ -79,18 +90,67 @@ inline ObjPtr<mirror::Class> ClassLinker::ResolveType(dex::TypeIndex type_idx,
if (kIsDebugBuild) {
Thread::Current()->AssertNoPendingException();
}
- ObjPtr<mirror::Class> resolved_type = referrer->GetDexCache()->GetResolvedType(type_idx);
+ // We do not need the read barrier for getting the DexCache for the initial resolved type
+ // lookup as both from-space and to-space copies point to the same native resolved types array.
+ ObjPtr<mirror::Class> resolved_type =
+ referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedType(type_idx);
if (UNLIKELY(resolved_type == nullptr)) {
StackHandleScope<2> hs(Thread::Current());
- ObjPtr<mirror::Class> declaring_class = referrer->GetDeclaringClass();
+ ObjPtr<mirror::Class> referring_class = referrer->GetDeclaringClass();
Handle<mirror::DexCache> dex_cache(hs.NewHandle(referrer->GetDexCache()));
- Handle<mirror::ClassLoader> class_loader(hs.NewHandle(declaring_class->GetClassLoader()));
- const DexFile& dex_file = *dex_cache->GetDexFile();
- resolved_type = ResolveType(dex_file, type_idx, dex_cache, class_loader);
+ Handle<mirror::ClassLoader> class_loader(hs.NewHandle(referring_class->GetClassLoader()));
+ resolved_type = DoResolveType(type_idx, dex_cache, class_loader);
}
return resolved_type;
}
+inline ObjPtr<mirror::Class> ClassLinker::ResolveType(dex::TypeIndex type_idx,
+ Handle<mirror::DexCache> dex_cache,
+ Handle<mirror::ClassLoader> class_loader) {
+ DCHECK(dex_cache != nullptr);
+ Thread::PoisonObjectPointersIfDebug();
+ ObjPtr<mirror::Class> resolved = dex_cache->GetResolvedType(type_idx);
+ if (resolved == nullptr) {
+ resolved = DoResolveType(type_idx, dex_cache, class_loader);
+ }
+ return resolved;
+}
+
+inline ObjPtr<mirror::Class> ClassLinker::LookupResolvedType(dex::TypeIndex type_idx,
+ ObjPtr<mirror::Class> referrer) {
+ // We do not need the read barrier for getting the DexCache for the initial resolved type
+ // lookup as both from-space and to-space copies point to the same native resolved types array.
+ ObjPtr<mirror::Class> type =
+ referrer->GetDexCache<kDefaultVerifyFlags, kWithoutReadBarrier>()->GetResolvedType(type_idx);
+ if (type == nullptr) {
+ type = DoLookupResolvedType(type_idx, referrer->GetDexCache(), referrer->GetClassLoader());
+ }
+ return type;
+}
+
+inline ObjPtr<mirror::Class> ClassLinker::LookupResolvedType(dex::TypeIndex type_idx,
+ ArtMethod* referrer) {
+ // We do not need the read barrier for getting the DexCache for the initial resolved type
+ // lookup as both from-space and to-space copies point to the same native resolved types array.
+ ObjPtr<mirror::Class> type =
+ referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedType(type_idx);
+ if (type == nullptr) {
+ type = DoLookupResolvedType(type_idx, referrer->GetDexCache(), referrer->GetClassLoader());
+ }
+ return type;
+}
+
+inline ObjPtr<mirror::Class> ClassLinker::LookupResolvedType(
+ dex::TypeIndex type_idx,
+ ObjPtr<mirror::DexCache> dex_cache,
+ ObjPtr<mirror::ClassLoader> class_loader) {
+ ObjPtr<mirror::Class> type = dex_cache->GetResolvedType(type_idx);
+ if (type == nullptr) {
+ type = DoLookupResolvedType(type_idx, dex_cache, class_loader);
+ }
+ return type;
+}
+
template <bool kThrowOnError, typename ClassGetter>
inline bool ClassLinker::CheckInvokeClassMismatch(ObjPtr<mirror::DexCache> dex_cache,
InvokeType type,
@@ -148,10 +208,9 @@ inline bool ClassLinker::CheckInvokeClassMismatch(ObjPtr<mirror::DexCache> dex_c
dex_cache,
type,
[this, dex_cache, method_idx, class_loader]() REQUIRES_SHARED(Locks::mutator_lock_) {
- const DexFile& dex_file = *dex_cache->GetDexFile();
- const DexFile::MethodId& method_id = dex_file.GetMethodId(method_idx);
+ const DexFile::MethodId& method_id = dex_cache->GetDexFile()->GetMethodId(method_idx);
ObjPtr<mirror::Class> klass =
- LookupResolvedType(dex_file, method_id.class_idx_, dex_cache, class_loader);
+ LookupResolvedType(method_id.class_idx_, dex_cache, class_loader);
DCHECK(klass != nullptr);
return klass;
});
@@ -187,6 +246,8 @@ inline ArtMethod* ClassLinker::GetResolvedMethod(uint32_t method_idx, ArtMethod*
// lookup in the context of the original method from where it steals the code.
// However, we delay the GetInterfaceMethodIfProxy() until needed.
DCHECK(!referrer->IsProxyMethod() || referrer->IsConstructor());
+ // We do not need the read barrier for getting the DexCache for the initial resolved method
+ // lookup as both from-space and to-space copies point to the same native resolved methods array.
ArtMethod* resolved_method = referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedMethod(
method_idx, image_pointer_size_);
if (resolved_method == nullptr) {
@@ -228,6 +289,8 @@ inline ArtMethod* ClassLinker::ResolveMethod(Thread* self,
// However, we delay the GetInterfaceMethodIfProxy() until needed.
DCHECK(!referrer->IsProxyMethod() || referrer->IsConstructor());
Thread::PoisonObjectPointersIfDebug();
+ // We do not need the read barrier for getting the DexCache for the initial resolved method
+ // lookup as both from-space and to-space copies point to the same native resolved methods array.
ArtMethod* resolved_method = referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedMethod(
method_idx, image_pointer_size_);
DCHECK(resolved_method == nullptr || !resolved_method->IsRuntimeMethod());
@@ -237,9 +300,7 @@ inline ArtMethod* ClassLinker::ResolveMethod(Thread* self,
StackHandleScope<2> hs(self);
Handle<mirror::DexCache> h_dex_cache(hs.NewHandle(referrer->GetDexCache()));
Handle<mirror::ClassLoader> h_class_loader(hs.NewHandle(declaring_class->GetClassLoader()));
- const DexFile* dex_file = h_dex_cache->GetDexFile();
- resolved_method = ResolveMethod<kResolveMode>(*dex_file,
- method_idx,
+ resolved_method = ResolveMethod<kResolveMode>(method_idx,
h_dex_cache,
h_class_loader,
referrer,
@@ -280,10 +341,13 @@ inline ArtMethod* ClassLinker::ResolveMethod(Thread* self,
inline ArtField* ClassLinker::LookupResolvedField(uint32_t field_idx,
ArtMethod* referrer,
bool is_static) {
- ObjPtr<mirror::DexCache> dex_cache = referrer->GetDexCache();
- ArtField* field = dex_cache->GetResolvedField(field_idx, image_pointer_size_);
+ // We do not need the read barrier for getting the DexCache for the initial resolved field
+ // lookup as both from-space and to-space copies point to the same native resolved fields array.
+ ArtField* field = referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedField(
+ field_idx, image_pointer_size_);
if (field == nullptr) {
- field = LookupResolvedField(field_idx, dex_cache, referrer->GetClassLoader(), is_static);
+ ObjPtr<mirror::ClassLoader> class_loader = referrer->GetDeclaringClass()->GetClassLoader();
+ field = LookupResolvedField(field_idx, referrer->GetDexCache(), class_loader, is_static);
}
return field;
}
@@ -292,13 +356,15 @@ inline ArtField* ClassLinker::ResolveField(uint32_t field_idx,
ArtMethod* referrer,
bool is_static) {
Thread::PoisonObjectPointersIfDebug();
- ObjPtr<mirror::Class> declaring_class = referrer->GetDeclaringClass();
- ArtField* resolved_field =
- referrer->GetDexCache()->GetResolvedField(field_idx, image_pointer_size_);
+ // We do not need the read barrier for getting the DexCache for the initial resolved field
+ // lookup as both from-space and to-space copies point to the same native resolved fields array.
+ ArtField* resolved_field = referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedField(
+ field_idx, image_pointer_size_);
if (UNLIKELY(resolved_field == nullptr)) {
StackHandleScope<2> hs(Thread::Current());
+ ObjPtr<mirror::Class> referring_class = referrer->GetDeclaringClass();
Handle<mirror::DexCache> dex_cache(hs.NewHandle(referrer->GetDexCache()));
- Handle<mirror::ClassLoader> class_loader(hs.NewHandle(declaring_class->GetClassLoader()));
+ Handle<mirror::ClassLoader> class_loader(hs.NewHandle(referring_class->GetClassLoader()));
resolved_field = ResolveField(field_idx, dex_cache, class_loader, is_static);
// Note: We cannot check here to see whether we added the field to the cache. The type
// might be an erroneous class, which results in it being hidden from us.
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 093ec6540c..55fa6328f5 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -5466,7 +5466,7 @@ bool ClassLinker::LoadSuperAndInterfaces(Handle<mirror::Class> klass, const DexF
return false;
}
- ObjPtr<mirror::Class> super_class = ResolveType(dex_file, super_class_idx, klass.Get());
+ ObjPtr<mirror::Class> super_class = ResolveType(super_class_idx, klass.Get());
if (super_class == nullptr) {
DCHECK(Thread::Current()->IsExceptionPending());
return false;
@@ -5485,7 +5485,7 @@ bool ClassLinker::LoadSuperAndInterfaces(Handle<mirror::Class> klass, const DexF
if (interfaces != nullptr) {
for (size_t i = 0; i < interfaces->Size(); i++) {
dex::TypeIndex idx = interfaces->GetTypeItem(i).type_idx_;
- ObjPtr<mirror::Class> interface = ResolveType(dex_file, idx, klass.Get());
+ ObjPtr<mirror::Class> interface = ResolveType(idx, klass.Get());
if (interface == nullptr) {
DCHECK(Thread::Current()->IsExceptionPending());
return false;
@@ -7762,74 +7762,56 @@ ObjPtr<mirror::String> ClassLinker::LookupString(dex::StringIndex string_idx,
return string;
}
-ObjPtr<mirror::Class> ClassLinker::LookupResolvedType(const DexFile& dex_file,
- dex::TypeIndex type_idx,
- ObjPtr<mirror::DexCache> dex_cache,
- ObjPtr<mirror::ClassLoader> class_loader) {
- ObjPtr<mirror::Class> type = dex_cache->GetResolvedType(type_idx);
- if (type == nullptr) {
- const char* descriptor = dex_file.StringByTypeIdx(type_idx);
- DCHECK_NE(*descriptor, '\0') << "descriptor is empty string";
- if (descriptor[1] == '\0') {
- // only the descriptors of primitive types should be 1 character long, also avoid class lookup
- // for primitive classes that aren't backed by dex files.
- type = FindPrimitiveClass(descriptor[0]);
+ObjPtr<mirror::Class> ClassLinker::DoLookupResolvedType(dex::TypeIndex type_idx,
+ ObjPtr<mirror::DexCache> dex_cache,
+ ObjPtr<mirror::ClassLoader> class_loader) {
+ const DexFile& dex_file = *dex_cache->GetDexFile();
+ const char* descriptor = dex_file.StringByTypeIdx(type_idx);
+ DCHECK_NE(*descriptor, '\0') << "descriptor is empty string";
+ ObjPtr<mirror::Class> type = nullptr;
+ if (descriptor[1] == '\0') {
+ // only the descriptors of primitive types should be 1 character long, also avoid class lookup
+ // for primitive classes that aren't backed by dex files.
+ type = FindPrimitiveClass(descriptor[0]);
+ } else {
+ Thread* const self = Thread::Current();
+ DCHECK(self != nullptr);
+ const size_t hash = ComputeModifiedUtf8Hash(descriptor);
+ // Find the class in the loaded classes table.
+ type = LookupClass(self, descriptor, hash, class_loader.Ptr());
+ }
+ if (type != nullptr) {
+ if (type->IsResolved()) {
+ dex_cache->SetResolvedType(type_idx, type);
} else {
- Thread* const self = Thread::Current();
- DCHECK(self != nullptr);
- const size_t hash = ComputeModifiedUtf8Hash(descriptor);
- // Find the class in the loaded classes table.
- type = LookupClass(self, descriptor, hash, class_loader.Ptr());
- }
- if (type != nullptr) {
- if (type->IsResolved()) {
- dex_cache->SetResolvedType(type_idx, type);
- } else {
- type = nullptr;
- }
+ type = nullptr;
}
}
- DCHECK(type == nullptr || type->IsResolved());
return type;
}
-ObjPtr<mirror::Class> ClassLinker::ResolveType(const DexFile& dex_file,
- dex::TypeIndex type_idx,
- ObjPtr<mirror::Class> referrer) {
- StackHandleScope<2> hs(Thread::Current());
- Handle<mirror::DexCache> dex_cache(hs.NewHandle(referrer->GetDexCache()));
- Handle<mirror::ClassLoader> class_loader(hs.NewHandle(referrer->GetClassLoader()));
- return ResolveType(dex_file, type_idx, dex_cache, class_loader);
-}
-
-ObjPtr<mirror::Class> ClassLinker::ResolveType(const DexFile& dex_file,
- dex::TypeIndex type_idx,
- Handle<mirror::DexCache> dex_cache,
- Handle<mirror::ClassLoader> class_loader) {
- DCHECK(dex_cache != nullptr);
- Thread::PoisonObjectPointersIfDebug();
- ObjPtr<mirror::Class> resolved = dex_cache->GetResolvedType(type_idx);
- if (resolved == nullptr) {
- Thread* self = Thread::Current();
- const char* descriptor = dex_file.StringByTypeIdx(type_idx);
- resolved = FindClass(self, descriptor, class_loader);
- if (resolved != nullptr) {
- // TODO: we used to throw here if resolved's class loader was not the
- // boot class loader. This was to permit different classes with the
- // same name to be loaded simultaneously by different loaders
- dex_cache->SetResolvedType(type_idx, resolved);
- } else {
- CHECK(self->IsExceptionPending())
- << "Expected pending exception for failed resolution of: " << descriptor;
- // Convert a ClassNotFoundException to a NoClassDefFoundError.
- StackHandleScope<1> hs(self);
- Handle<mirror::Throwable> cause(hs.NewHandle(self->GetException()));
- if (cause->InstanceOf(GetClassRoot(kJavaLangClassNotFoundException))) {
- DCHECK(resolved == nullptr); // No Handle needed to preserve resolved.
- self->ClearException();
- ThrowNoClassDefFoundError("Failed resolution of: %s", descriptor);
- self->GetException()->SetCause(cause.Get());
- }
+ObjPtr<mirror::Class> ClassLinker::DoResolveType(dex::TypeIndex type_idx,
+ Handle<mirror::DexCache> dex_cache,
+ Handle<mirror::ClassLoader> class_loader) {
+ Thread* self = Thread::Current();
+ const char* descriptor = dex_cache->GetDexFile()->StringByTypeIdx(type_idx);
+ ObjPtr<mirror::Class> resolved = FindClass(self, descriptor, class_loader);
+ if (resolved != nullptr) {
+ // TODO: we used to throw here if resolved's class loader was not the
+ // boot class loader. This was to permit different classes with the
+ // same name to be loaded simultaneously by different loaders
+ dex_cache->SetResolvedType(type_idx, resolved);
+ } else {
+ CHECK(self->IsExceptionPending())
+ << "Expected pending exception for failed resolution of: " << descriptor;
+ // Convert a ClassNotFoundException to a NoClassDefFoundError.
+ StackHandleScope<1> hs(self);
+ Handle<mirror::Throwable> cause(hs.NewHandle(self->GetException()));
+ if (cause->InstanceOf(GetClassRoot(kJavaLangClassNotFoundException))) {
+ DCHECK(resolved == nullptr); // No Handle needed to preserve resolved.
+ self->ClearException();
+ ThrowNoClassDefFoundError("Failed resolution of: %s", descriptor);
+ self->GetException()->SetCause(cause.Get());
}
}
DCHECK((resolved == nullptr) || resolved->IsResolved())
@@ -7938,8 +7920,7 @@ std::string DescribeLoaders(ObjPtr<mirror::ClassLoader> loader, const char* clas
}
template <ClassLinker::ResolveMode kResolveMode>
-ArtMethod* ClassLinker::ResolveMethod(const DexFile& dex_file,
- uint32_t method_idx,
+ArtMethod* ClassLinker::ResolveMethod(uint32_t method_idx,
Handle<mirror::DexCache> dex_cache,
Handle<mirror::ClassLoader> class_loader,
ArtMethod* referrer,
@@ -7957,12 +7938,13 @@ ArtMethod* ClassLinker::ResolveMethod(const DexFile& dex_file,
DCHECK(resolved->GetDeclaringClassUnchecked() != nullptr) << resolved->GetDexMethodIndex();
return resolved;
}
+ const DexFile& dex_file = *dex_cache->GetDexFile();
const DexFile::MethodId& method_id = dex_file.GetMethodId(method_idx);
ObjPtr<mirror::Class> klass = nullptr;
if (valid_dex_cache_method) {
// We have a valid method from the DexCache but we need to perform ICCE and IAE checks.
DCHECK(resolved->GetDeclaringClassUnchecked() != nullptr) << resolved->GetDexMethodIndex();
- klass = LookupResolvedType(dex_file, method_id.class_idx_, dex_cache.Get(), class_loader.Get());
+ klass = LookupResolvedType(method_id.class_idx_, dex_cache.Get(), class_loader.Get());
if (UNLIKELY(klass == nullptr)) {
const char* descriptor = dex_file.StringByTypeIdx(method_id.class_idx_);
LOG(FATAL) << "Check failed: klass != nullptr Bug: 64759619 Method: "
@@ -7973,7 +7955,7 @@ ArtMethod* ClassLinker::ResolveMethod(const DexFile& dex_file,
}
} else {
// The method was not in the DexCache, resolve the declaring class.
- klass = ResolveType(dex_file, method_id.class_idx_, dex_cache, class_loader);
+ klass = ResolveType(method_id.class_idx_, dex_cache, class_loader);
if (klass == nullptr) {
DCHECK(Thread::Current()->IsExceptionPending());
return nullptr;
@@ -8048,8 +8030,7 @@ ArtMethod* ClassLinker::ResolveMethod(const DexFile& dex_file,
}
}
-ArtMethod* ClassLinker::ResolveMethodWithoutInvokeType(const DexFile& dex_file,
- uint32_t method_idx,
+ArtMethod* ClassLinker::ResolveMethodWithoutInvokeType(uint32_t method_idx,
Handle<mirror::DexCache> dex_cache,
Handle<mirror::ClassLoader> class_loader) {
ArtMethod* resolved = dex_cache->GetResolvedMethod(method_idx, image_pointer_size_);
@@ -8060,9 +8041,8 @@ ArtMethod* ClassLinker::ResolveMethodWithoutInvokeType(const DexFile& dex_file,
return resolved;
}
// Fail, get the declaring class.
- const DexFile::MethodId& method_id = dex_file.GetMethodId(method_idx);
- ObjPtr<mirror::Class> klass =
- ResolveType(dex_file, method_id.class_idx_, dex_cache, class_loader);
+ const DexFile::MethodId& method_id = dex_cache->GetDexFile()->GetMethodId(method_idx);
+ ObjPtr<mirror::Class> klass = ResolveType(method_id.class_idx_, dex_cache, class_loader);
if (klass == nullptr) {
Thread::Current()->AssertPendingException();
return nullptr;
@@ -8084,7 +8064,7 @@ ArtField* ClassLinker::LookupResolvedField(uint32_t field_idx,
const DexFile::FieldId& field_id = dex_file.GetFieldId(field_idx);
ObjPtr<mirror::Class> klass = dex_cache->GetResolvedType(field_id.class_idx_);
if (klass == nullptr) {
- klass = LookupResolvedType(dex_file, field_id.class_idx_, dex_cache, class_loader);
+ klass = LookupResolvedType(field_id.class_idx_, dex_cache, class_loader);
}
if (klass == nullptr) {
// The class has not been resolved yet, so the field is also unresolved.
@@ -8126,7 +8106,7 @@ ArtField* ClassLinker::ResolveField(uint32_t field_idx,
const DexFile& dex_file = *dex_cache->GetDexFile();
const DexFile::FieldId& field_id = dex_file.GetFieldId(field_idx);
Thread* const self = Thread::Current();
- ObjPtr<mirror::Class> klass = ResolveType(dex_file, field_id.class_idx_, dex_cache, class_loader);
+ ObjPtr<mirror::Class> klass = ResolveType(field_id.class_idx_, dex_cache, class_loader);
if (klass == nullptr) {
DCHECK(Thread::Current()->IsExceptionPending());
return nullptr;
@@ -8167,7 +8147,7 @@ ArtField* ClassLinker::ResolveFieldJLS(uint32_t field_idx,
const DexFile& dex_file = *dex_cache->GetDexFile();
const DexFile::FieldId& field_id = dex_file.GetFieldId(field_idx);
Thread* self = Thread::Current();
- ObjPtr<mirror::Class> klass(ResolveType(dex_file, field_id.class_idx_, dex_cache, class_loader));
+ ObjPtr<mirror::Class> klass = ResolveType(field_id.class_idx_, dex_cache, class_loader);
if (klass == nullptr) {
DCHECK(Thread::Current()->IsExceptionPending());
return nullptr;
@@ -8203,7 +8183,7 @@ ObjPtr<mirror::MethodType> ClassLinker::ResolveMethodType(
const DexFile& dex_file = *dex_cache->GetDexFile();
const DexFile::ProtoId& proto_id = dex_file.GetProtoId(proto_idx);
Handle<mirror::Class> return_type(hs.NewHandle(
- ResolveType(dex_file, proto_id.return_type_idx_, dex_cache, class_loader)));
+ ResolveType(proto_id.return_type_idx_, dex_cache, class_loader)));
if (return_type == nullptr) {
DCHECK(self->IsExceptionPending());
return nullptr;
@@ -8229,7 +8209,7 @@ ObjPtr<mirror::MethodType> ClassLinker::ResolveMethodType(
MutableHandle<mirror::Class> param_class = hs.NewHandle<mirror::Class>(nullptr);
for (; it.HasNext(); it.Next()) {
const dex::TypeIndex type_idx = it.GetTypeIdx();
- param_class.Assign(ResolveType(dex_file, type_idx, dex_cache, class_loader));
+ param_class.Assign(ResolveType(type_idx, dex_cache, class_loader));
if (param_class == nullptr) {
DCHECK(self->IsExceptionPending());
return nullptr;
@@ -8431,8 +8411,7 @@ mirror::MethodHandle* ClassLinker::ResolveMethodHandleForMethod(
// the invocation type to determine if the method is private. We
// then resolve again specifying the intended invocation type to
// force the appropriate checks.
- target_method = ResolveMethodWithoutInvokeType(*dex_file,
- method_handle.field_or_method_idx_,
+ target_method = ResolveMethodWithoutInvokeType(method_handle.field_or_method_idx_,
hs.NewHandle(referrer->GetDexCache()),
hs.NewHandle(referrer->GetClassLoader()));
if (UNLIKELY(target_method == nullptr)) {
@@ -8515,7 +8494,7 @@ mirror::MethodHandle* ClassLinker::ResolveMethodHandleForMethod(
DexFileParameterIterator it(*dex_file, target_method->GetPrototype());
while (it.HasNext()) {
const dex::TypeIndex type_idx = it.GetTypeIdx();
- ObjPtr<mirror::Class> klass = ResolveType(*dex_file, type_idx, dex_cache, class_loader);
+ ObjPtr<mirror::Class> klass = ResolveType(type_idx, dex_cache, class_loader);
if (nullptr == klass) {
DCHECK(self->IsExceptionPending());
return nullptr;
@@ -9033,14 +9012,12 @@ mirror::IfTable* ClassLinker::AllocIfTable(Thread* self, size_t ifcount) {
// Instantiate ResolveMethod.
template ArtMethod* ClassLinker::ResolveMethod<ClassLinker::ResolveMode::kCheckICCEAndIAE>(
- const DexFile& dex_file,
uint32_t method_idx,
Handle<mirror::DexCache> dex_cache,
Handle<mirror::ClassLoader> class_loader,
ArtMethod* referrer,
InvokeType type);
template ArtMethod* ClassLinker::ResolveMethod<ClassLinker::ResolveMode::kNoChecks>(
- const DexFile& dex_file,
uint32_t method_idx,
Handle<mirror::DexCache> dex_cache,
Handle<mirror::ClassLoader> class_loader,
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 6a5768ec27..10562f0890 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -255,45 +255,50 @@ class ClassLinker {
ObjPtr<mirror::DexCache> dex_cache)
REQUIRES_SHARED(Locks::mutator_lock_);
- // Resolve a Type with the given index from the DexFile, storing the
- // result in the DexCache. The referrer is used to identify the
- // target DexCache and ClassLoader to use for resolution.
- ObjPtr<mirror::Class> ResolveType(const DexFile& dex_file,
- dex::TypeIndex type_idx,
- ObjPtr<mirror::Class> referrer)
+ // Resolve a Type with the given index from the DexFile associated with the given `referrer`,
+ // storing the result in the DexCache. The `referrer` is used to identify the target DexCache
+ // and ClassLoader to use for resolution.
+ ObjPtr<mirror::Class> ResolveType(dex::TypeIndex type_idx, ObjPtr<mirror::Class> referrer)
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_);
- // Resolve a Type with the given index from the DexFile, storing the
- // result in the DexCache. The referrer is used to identify the
- // target DexCache and ClassLoader to use for resolution.
+ // Resolve a type with the given index from the DexFile associated with the given `referrer`,
+ // storing the result in the DexCache. The `referrer` is used to identify the target DexCache
+ // and ClassLoader to use for resolution.
ObjPtr<mirror::Class> ResolveType(dex::TypeIndex type_idx, ArtMethod* referrer)
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_);
- // Look up a resolved type with the given ID from the DexFile. The ClassLoader is used to search
- // for the type, since it may be referenced from but not contained within the given DexFile.
- ObjPtr<mirror::Class> LookupResolvedType(const DexFile& dex_file,
- dex::TypeIndex type_idx,
- ObjPtr<mirror::DexCache> dex_cache,
- ObjPtr<mirror::ClassLoader> class_loader)
- REQUIRES_SHARED(Locks::mutator_lock_);
- static ObjPtr<mirror::Class> LookupResolvedType(dex::TypeIndex type_idx,
- ObjPtr<mirror::DexCache> dex_cache,
- ObjPtr<mirror::ClassLoader> class_loader)
- REQUIRES_SHARED(Locks::mutator_lock_);
-
- // Resolve a type with the given ID from the DexFile, storing the
- // result in DexCache. The ClassLoader is used to search for the
- // type, since it may be referenced from but not contained within
- // the given DexFile.
- ObjPtr<mirror::Class> ResolveType(const DexFile& dex_file,
- dex::TypeIndex type_idx,
+ // Resolve a type with the given index from the DexFile associated with the given DexCache
+ // and ClassLoader, storing the result in DexCache. The ClassLoader is used to search for
+ // the type, since it may be referenced from but not contained within the DexFile.
+ ObjPtr<mirror::Class> ResolveType(dex::TypeIndex type_idx,
Handle<mirror::DexCache> dex_cache,
Handle<mirror::ClassLoader> class_loader)
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_);
+ // Look up a resolved type with the given index from the DexFile associated with the given
+ // `referrer`, storing the result in the DexCache. The `referrer` is used to identify the
+ // target DexCache and ClassLoader to use for lookup.
+ ObjPtr<mirror::Class> LookupResolvedType(dex::TypeIndex type_idx,
+ ObjPtr<mirror::Class> referrer)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
+ // Look up a resolved type with the given index from the DexFile associated with the given
+ // `referrer`, storing the result in the DexCache. The `referrer` is used to identify the
+ // target DexCache and ClassLoader to use for lookup.
+ ObjPtr<mirror::Class> LookupResolvedType(dex::TypeIndex type_idx, ArtMethod* referrer)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
+ // Look up a resolved type with the given index from the DexFile associated with the given
+ // DexCache and ClassLoader. The ClassLoader is used to search for the type, since it may
+ // be referenced from but not contained within the DexFile.
+ ObjPtr<mirror::Class> LookupResolvedType(dex::TypeIndex type_idx,
+ ObjPtr<mirror::DexCache> dex_cache,
+ ObjPtr<mirror::ClassLoader> class_loader)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
// Determine whether a dex cache result should be trusted, or an IncompatibleClassChangeError
// check and IllegalAccessError check should be performed even after a hit.
enum class ResolveMode { // private.
@@ -307,14 +312,12 @@ class ClassLinker {
ObjPtr<mirror::ClassLoader> class_loader)
REQUIRES_SHARED(Locks::mutator_lock_);
- // Resolve a method with a given ID from the DexFile, storing the
- // result in DexCache. The ClassLinker and ClassLoader are used as
- // in ResolveType. What is unique is the method type argument which
- // is used to determine if this method is a direct, static, or
- // virtual method.
+ // Resolve a method with a given ID from the DexFile associated with the given DexCache
+ // and ClassLoader, storing the result in DexCache. The ClassLinker and ClassLoader are
+ // used as in ResolveType. What is unique is the method type argument which is used to
+ // determine if this method is a direct, static, or virtual method.
template <ResolveMode kResolveMode>
- ArtMethod* ResolveMethod(const DexFile& dex_file,
- uint32_t method_idx,
+ ArtMethod* ResolveMethod(uint32_t method_idx,
Handle<mirror::DexCache> dex_cache,
Handle<mirror::ClassLoader> class_loader,
ArtMethod* referrer,
@@ -330,8 +333,7 @@ class ClassLinker {
ArtMethod* ResolveMethod(Thread* self, uint32_t method_idx, ArtMethod* referrer, InvokeType type)
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_);
- ArtMethod* ResolveMethodWithoutInvokeType(const DexFile& dex_file,
- uint32_t method_idx,
+ ArtMethod* ResolveMethodWithoutInvokeType(uint32_t method_idx,
Handle<mirror::DexCache> dex_cache,
Handle<mirror::ClassLoader> class_loader)
REQUIRES_SHARED(Locks::mutator_lock_)
@@ -879,6 +881,19 @@ class ClassLinker {
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!Locks::dex_lock_);
+ // Implementation of LookupResolvedType() called when the type was not found in the dex cache.
+ ObjPtr<mirror::Class> DoLookupResolvedType(dex::TypeIndex type_idx,
+ ObjPtr<mirror::DexCache> dex_cache,
+ ObjPtr<mirror::ClassLoader> class_loader)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
+ // Implementation of ResolveType() called when the type was not found in the dex cache.
+ ObjPtr<mirror::Class> DoResolveType(dex::TypeIndex type_idx,
+ Handle<mirror::DexCache> dex_cache,
+ Handle<mirror::ClassLoader> class_loader)
+ REQUIRES_SHARED(Locks::mutator_lock_)
+ REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_);
+
// Finds a class by its descriptor, returning NULL if it isn't wasn't loaded
// by the given 'class_loader'. Uses the provided hash for the descriptor.
mirror::Class* LookupClass(Thread* self,
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index b625c40fc3..246f89e5cc 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -954,15 +954,14 @@ TEST_F(ClassLinkerTest, LookupResolvedType) {
ObjPtr<mirror::Class> klass = class_linker_->FindClass(soa.Self(), "LMyClass;", class_loader);
dex::TypeIndex type_idx = klass->GetClassDef()->class_idx_;
ObjPtr<mirror::DexCache> dex_cache = klass->GetDexCache();
- const DexFile& dex_file = klass->GetDexFile();
EXPECT_OBJ_PTR_EQ(
- class_linker_->LookupResolvedType(dex_file, type_idx, dex_cache, class_loader.Get()),
+ class_linker_->LookupResolvedType(type_idx, dex_cache, class_loader.Get()),
klass);
// Zero out the resolved type and make sure LookupResolvedType still finds it.
dex_cache->ClearResolvedType(type_idx);
EXPECT_TRUE(dex_cache->GetResolvedType(type_idx) == nullptr);
EXPECT_OBJ_PTR_EQ(
- class_linker_->LookupResolvedType(dex_file, type_idx, dex_cache, class_loader.Get()),
+ class_linker_->LookupResolvedType(type_idx, dex_cache, class_loader.Get()),
klass);
}
@@ -983,7 +982,7 @@ TEST_F(ClassLinkerTest, LookupResolvedTypeArray) {
dex::TypeIndex array_idx = dex_file.GetIndexForTypeId(*array_id);
// Check that the array class wasn't resolved yet.
EXPECT_OBJ_PTR_EQ(
- class_linker_->LookupResolvedType(dex_file, array_idx, dex_cache.Get(), class_loader.Get()),
+ class_linker_->LookupResolvedType(array_idx, dex_cache.Get(), class_loader.Get()),
ObjPtr<mirror::Class>(nullptr));
// Resolve the array class we want to test.
ObjPtr<mirror::Class> array_klass
@@ -991,13 +990,13 @@ TEST_F(ClassLinkerTest, LookupResolvedTypeArray) {
ASSERT_OBJ_PTR_NE(array_klass, ObjPtr<mirror::Class>(nullptr));
// Test that LookupResolvedType() finds the array class.
EXPECT_OBJ_PTR_EQ(
- class_linker_->LookupResolvedType(dex_file, array_idx, dex_cache.Get(), class_loader.Get()),
+ class_linker_->LookupResolvedType(array_idx, dex_cache.Get(), class_loader.Get()),
array_klass);
// Zero out the resolved type and make sure LookupResolvedType() still finds it.
dex_cache->ClearResolvedType(array_idx);
EXPECT_TRUE(dex_cache->GetResolvedType(array_idx) == nullptr);
EXPECT_OBJ_PTR_EQ(
- class_linker_->LookupResolvedType(dex_file, array_idx, dex_cache.Get(), class_loader.Get()),
+ class_linker_->LookupResolvedType(array_idx, dex_cache.Get(), class_loader.Get()),
array_klass);
}
@@ -1012,15 +1011,14 @@ TEST_F(ClassLinkerTest, LookupResolvedTypeErroneousInit) {
ASSERT_OBJ_PTR_NE(klass.Get(), ObjPtr<mirror::Class>(nullptr));
dex::TypeIndex type_idx = klass->GetClassDef()->class_idx_;
Handle<mirror::DexCache> dex_cache = hs.NewHandle(klass->GetDexCache());
- const DexFile& dex_file = klass->GetDexFile();
EXPECT_OBJ_PTR_EQ(
- class_linker_->LookupResolvedType(dex_file, type_idx, dex_cache.Get(), class_loader.Get()),
+ class_linker_->LookupResolvedType(type_idx, dex_cache.Get(), class_loader.Get()),
klass.Get());
// Zero out the resolved type and make sure LookupResolvedType still finds it.
dex_cache->ClearResolvedType(type_idx);
EXPECT_TRUE(dex_cache->GetResolvedType(type_idx) == nullptr);
EXPECT_OBJ_PTR_EQ(
- class_linker_->LookupResolvedType(dex_file, type_idx, dex_cache.Get(), class_loader.Get()),
+ class_linker_->LookupResolvedType(type_idx, dex_cache.Get(), class_loader.Get()),
klass.Get());
// Force initialization to turn the class erroneous.
bool initialized = class_linker_->EnsureInitialized(soa.Self(),
@@ -1032,13 +1030,13 @@ TEST_F(ClassLinkerTest, LookupResolvedTypeErroneousInit) {
soa.Self()->ClearException();
// Check that the LookupResolvedType() can still find the resolved type.
EXPECT_OBJ_PTR_EQ(
- class_linker_->LookupResolvedType(dex_file, type_idx, dex_cache.Get(), class_loader.Get()),
+ class_linker_->LookupResolvedType(type_idx, dex_cache.Get(), class_loader.Get()),
klass.Get());
// Zero out the resolved type and make sure LookupResolvedType() still finds it.
dex_cache->ClearResolvedType(type_idx);
EXPECT_TRUE(dex_cache->GetResolvedType(type_idx) == nullptr);
EXPECT_OBJ_PTR_EQ(
- class_linker_->LookupResolvedType(dex_file, type_idx, dex_cache.Get(), class_loader.Get()),
+ class_linker_->LookupResolvedType(type_idx, dex_cache.Get(), class_loader.Get()),
klass.Get());
}
diff --git a/runtime/code_item_accessors-inl.h b/runtime/code_item_accessors-inl.h
index d04849d09a..4f4d8cc86e 100644
--- a/runtime/code_item_accessors-inl.h
+++ b/runtime/code_item_accessors-inl.h
@@ -22,6 +22,7 @@
#include "art_method-inl.h"
#include "cdex/compact_dex_file.h"
#include "dex_file-inl.h"
+#include "oat_file.h"
#include "standard_dex_file.h"
namespace art {
@@ -37,7 +38,7 @@ inline void CodeItemInstructionAccessor::Init(const StandardDexFile::CodeItem& c
}
inline void CodeItemInstructionAccessor::Init(const DexFile* dex_file,
- const DexFile::CodeItem* code_item) {
+ const DexFile::CodeItem* code_item) {
DCHECK(dex_file != nullptr);
DCHECK(code_item != nullptr);
if (dex_file->IsCompactDexFile()) {
@@ -150,6 +151,31 @@ inline const DexFile::TryItem* CodeItemDataAccessor::FindTryItem(uint32_t try_de
return index != -1 ? &try_items.begin()[index] : nullptr;
}
+inline CodeItemDebugInfoAccessor::CodeItemDebugInfoAccessor(ArtMethod* method)
+ : CodeItemDebugInfoAccessor(method->GetDexFile(), method->GetCodeItem()) {}
+
+inline CodeItemDebugInfoAccessor::CodeItemDebugInfoAccessor(const DexFile* dex_file,
+ const DexFile::CodeItem* code_item) {
+ if (code_item == nullptr) {
+ return;
+ }
+ debug_info_offset_ = OatFile::GetDebugInfoOffset(*dex_file, code_item);
+ if (dex_file->IsCompactDexFile()) {
+ Init(down_cast<const CompactDexFile::CodeItem&>(*code_item));
+ } else {
+ DCHECK(dex_file->IsStandardDexFile());
+ Init(down_cast<const StandardDexFile::CodeItem&>(*code_item));
+ }
+}
+
+inline void CodeItemDebugInfoAccessor::Init(const CompactDexFile::CodeItem& code_item) {
+ CodeItemDataAccessor::Init(code_item);
+}
+
+inline void CodeItemDebugInfoAccessor::Init(const StandardDexFile::CodeItem& code_item) {
+ CodeItemDataAccessor::Init(code_item);
+}
+
} // namespace art
#endif // ART_RUNTIME_CODE_ITEM_ACCESSORS_INL_H_
diff --git a/runtime/code_item_accessors.h b/runtime/code_item_accessors.h
index aa1305acad..a089a276de 100644
--- a/runtime/code_item_accessors.h
+++ b/runtime/code_item_accessors.h
@@ -132,6 +132,30 @@ class CodeItemDataAccessor : public CodeItemInstructionAccessor {
uint16_t tries_size_;
};
+// Abstract accesses to code item data including debug info offset. More heavy weight than the other
+// helpers.
+class CodeItemDebugInfoAccessor : public CodeItemDataAccessor {
+ public:
+ CodeItemDebugInfoAccessor() = default;
+
+ // Handles null code items, but not null dex files.
+ ALWAYS_INLINE CodeItemDebugInfoAccessor(const DexFile* dex_file,
+ const DexFile::CodeItem* code_item);
+
+ ALWAYS_INLINE explicit CodeItemDebugInfoAccessor(ArtMethod* method);
+
+ uint32_t DebugInfoOffset() const {
+ return debug_info_offset_;
+ }
+
+ protected:
+ ALWAYS_INLINE void Init(const CompactDexFile::CodeItem& code_item);
+ ALWAYS_INLINE void Init(const StandardDexFile::CodeItem& code_item);
+
+ private:
+ uint32_t debug_info_offset_ = 0u;
+};
+
} // namespace art
#endif // ART_RUNTIME_CODE_ITEM_ACCESSORS_H_
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index 13029fb958..b5ae09f701 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -1661,16 +1661,16 @@ void Dbg::OutputLineTable(JDWP::RefTypeId, JDWP::MethodId method_id, JDWP::Expan
}
};
ArtMethod* m = FromMethodId(method_id);
- const DexFile::CodeItem* code_item = m->GetCodeItem();
+ CodeItemDebugInfoAccessor accessor(m);
uint64_t start, end;
- if (code_item == nullptr) {
+ if (!accessor.HasCodeItem()) {
DCHECK(m->IsNative() || m->IsProxyMethod());
start = -1;
end = -1;
} else {
start = 0;
// Return the index of the last instruction
- end = code_item->insns_size_in_code_units_ - 1;
+ end = accessor.InsnsSizeInCodeUnits() - 1;
}
expandBufAdd8BE(pReply, start);
@@ -1684,10 +1684,10 @@ void Dbg::OutputLineTable(JDWP::RefTypeId, JDWP::MethodId method_id, JDWP::Expan
context.numItems = 0;
context.pReply = pReply;
- if (code_item != nullptr) {
- uint32_t debug_info_offset = OatFile::GetDebugInfoOffset(*(m->GetDexFile()), code_item);
- m->GetDexFile()->DecodeDebugPositionInfo(
- code_item, debug_info_offset, DebugCallbackContext::Callback, &context);
+ if (accessor.HasCodeItem()) {
+ m->GetDexFile()->DecodeDebugPositionInfo(accessor.DebugInfoOffset(),
+ DebugCallbackContext::Callback,
+ &context);
}
JDWP::Set4BE(expandBufGetBuffer(pReply) + numLinesOffset, context.numItems);
@@ -1727,6 +1727,7 @@ void Dbg::OutputVariableTable(JDWP::RefTypeId, JDWP::MethodId method_id, bool wi
}
};
ArtMethod* m = FromMethodId(method_id);
+ CodeItemDebugInfoAccessor accessor(m);
// arg_count considers doubles and longs to take 2 units.
// variable_count considers everything to take 1 unit.
@@ -1742,12 +1743,15 @@ void Dbg::OutputVariableTable(JDWP::RefTypeId, JDWP::MethodId method_id, bool wi
context.variable_count = 0;
context.with_generic = with_generic;
- const DexFile::CodeItem* code_item = m->GetCodeItem();
- if (code_item != nullptr) {
- uint32_t debug_info_offset = OatFile::GetDebugInfoOffset(*(m->GetDexFile()), code_item);
- m->GetDexFile()->DecodeDebugLocalInfo(
- code_item, debug_info_offset, m->IsStatic(), m->GetDexMethodIndex(),
- DebugCallbackContext::Callback, &context);
+ if (accessor.HasCodeItem()) {
+ m->GetDexFile()->DecodeDebugLocalInfo(accessor.RegistersSize(),
+ accessor.InsSize(),
+ accessor.InsnsSizeInCodeUnits(),
+ accessor.DebugInfoOffset(),
+ m->IsStatic(),
+ m->GetDexMethodIndex(),
+ DebugCallbackContext::Callback,
+ &context);
}
JDWP::Set4BE(expandBufGetBuffer(pReply) + variable_count_offset, context.variable_count);
@@ -3836,9 +3840,9 @@ JDWP::JdwpError Dbg::ConfigureStep(JDWP::ObjectId thread_id, JDWP::JdwpStepSize
// Find the dex_pc values that correspond to the current line, for line-based single-stepping.
struct DebugCallbackContext {
DebugCallbackContext(SingleStepControl* single_step_control_cb,
- int32_t line_number_cb, const DexFile::CodeItem* code_item)
+ int32_t line_number_cb, uint32_t num_insns_in_code_units)
: single_step_control_(single_step_control_cb), line_number_(line_number_cb),
- code_item_(code_item), last_pc_valid(false), last_pc(0) {
+ num_insns_in_code_units_(num_insns_in_code_units), last_pc_valid(false), last_pc(0) {
}
static bool Callback(void* raw_context, const DexFile::PositionInfo& entry) {
@@ -3864,8 +3868,7 @@ JDWP::JdwpError Dbg::ConfigureStep(JDWP::ObjectId thread_id, JDWP::JdwpStepSize
~DebugCallbackContext() {
// If the line number was the last in the position table...
if (last_pc_valid) {
- size_t end = code_item_->insns_size_in_code_units_;
- for (uint32_t dex_pc = last_pc; dex_pc < end; ++dex_pc) {
+ for (uint32_t dex_pc = last_pc; dex_pc < num_insns_in_code_units_; ++dex_pc) {
single_step_control_->AddDexPc(dex_pc);
}
}
@@ -3873,7 +3876,7 @@ JDWP::JdwpError Dbg::ConfigureStep(JDWP::ObjectId thread_id, JDWP::JdwpStepSize
SingleStepControl* const single_step_control_;
const int32_t line_number_;
- const DexFile::CodeItem* const code_item_;
+ const uint32_t num_insns_in_code_units_;
bool last_pc_valid;
uint32_t last_pc;
};
@@ -3892,11 +3895,11 @@ JDWP::JdwpError Dbg::ConfigureStep(JDWP::ObjectId thread_id, JDWP::JdwpStepSize
// Note: if the thread is not running Java code (pure native thread), there is no "current"
// method on the stack (and no line number either).
if (m != nullptr && !m->IsNative()) {
- const DexFile::CodeItem* const code_item = m->GetCodeItem();
- DebugCallbackContext context(single_step_control, line_number, code_item);
- uint32_t debug_info_offset = OatFile::GetDebugInfoOffset(*(m->GetDexFile()), code_item);
- m->GetDexFile()->DecodeDebugPositionInfo(
- code_item, debug_info_offset, DebugCallbackContext::Callback, &context);
+ CodeItemDebugInfoAccessor accessor(m);
+ DebugCallbackContext context(single_step_control, line_number, accessor.InsnsSizeInCodeUnits());
+ m->GetDexFile()->DecodeDebugPositionInfo(accessor.DebugInfoOffset(),
+ DebugCallbackContext::Callback,
+ &context);
}
// Activate single-step in the thread.
@@ -4376,15 +4379,20 @@ bool Dbg::DdmHandleChunk(JNIEnv* env,
replyData.get(),
offset,
length);
- if (length == 0 || replyData.get() == nullptr) {
- return false;
- }
-
out_data->resize(length);
env->GetByteArrayRegion(replyData.get(),
offset,
length,
reinterpret_cast<jbyte*>(out_data->data()));
+
+ if (env->ExceptionCheck()) {
+ LOG(INFO) << StringPrintf("Exception thrown when reading response data from dispatcher 0x%08x",
+ type);
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ return false;
+ }
+
return true;
}
@@ -4418,7 +4426,7 @@ bool Dbg::DdmHandlePacket(JDWP::Request* request, uint8_t** pReplyBuf, int* pRep
std::vector<uint8_t> out_data;
uint32_t out_type = 0;
request->Skip(request_length);
- if (!DdmHandleChunk(env, type, data, &out_type, &out_data)) {
+ if (!DdmHandleChunk(env, type, data, &out_type, &out_data) || out_data.empty()) {
return false;
}
const uint32_t kDdmHeaderSize = 8;
diff --git a/runtime/dex_file-inl.h b/runtime/dex_file-inl.h
index 4025a1a0f9..a6f762120c 100644
--- a/runtime/dex_file-inl.h
+++ b/runtime/dex_file-inl.h
@@ -384,13 +384,16 @@ bool DexFile::DecodeDebugLocalInfo(const uint8_t* stream,
}
template<typename NewLocalCallback>
-bool DexFile::DecodeDebugLocalInfo(const CodeItem* code_item,
+bool DexFile::DecodeDebugLocalInfo(uint32_t registers_size,
+ uint32_t ins_size,
+ uint32_t insns_size_in_code_units,
uint32_t debug_info_offset,
bool is_static,
uint32_t method_idx,
NewLocalCallback new_local_callback,
void* context) const {
- if (code_item == nullptr) {
+ const uint8_t* const stream = GetDebugInfoStream(debug_info_offset);
+ if (stream == nullptr) {
return false;
}
std::vector<const char*> arg_descriptors;
@@ -398,15 +401,15 @@ bool DexFile::DecodeDebugLocalInfo(const CodeItem* code_item,
for (; it.HasNext(); it.Next()) {
arg_descriptors.push_back(it.GetDescriptor());
}
- return DecodeDebugLocalInfo(GetDebugInfoStream(debug_info_offset),
+ return DecodeDebugLocalInfo(stream,
GetLocation(),
GetMethodDeclaringClassDescriptor(GetMethodId(method_idx)),
arg_descriptors,
this->PrettyMethod(method_idx),
is_static,
- code_item->registers_size_,
- code_item->ins_size_,
- code_item->insns_size_in_code_units_,
+ registers_size,
+ ins_size,
+ insns_size_in_code_units,
[this](uint32_t idx) {
return StringDataByIdx(dex::StringIndex(idx));
},
@@ -487,13 +490,9 @@ bool DexFile::DecodeDebugPositionInfo(const uint8_t* stream,
}
template<typename DexDebugNewPosition>
-bool DexFile::DecodeDebugPositionInfo(const CodeItem* code_item,
- uint32_t debug_info_offset,
+bool DexFile::DecodeDebugPositionInfo(uint32_t debug_info_offset,
DexDebugNewPosition position_functor,
void* context) const {
- if (code_item == nullptr) {
- return false;
- }
return DecodeDebugPositionInfo(GetDebugInfoStream(debug_info_offset),
[this](uint32_t idx) {
return StringDataByIdx(dex::StringIndex(idx));
diff --git a/runtime/dex_file.h b/runtime/dex_file.h
index 561b3678b4..de3af8a289 100644
--- a/runtime/dex_file.h
+++ b/runtime/dex_file.h
@@ -956,7 +956,9 @@ class DexFile {
NewLocalCallback new_local,
void* context);
template<typename NewLocalCallback>
- bool DecodeDebugLocalInfo(const CodeItem* code_item,
+ bool DecodeDebugLocalInfo(uint32_t registers_size,
+ uint32_t ins_size,
+ uint32_t insns_size_in_code_units,
uint32_t debug_info_offset,
bool is_static,
uint32_t method_idx,
@@ -970,8 +972,7 @@ class DexFile {
DexDebugNewPosition position_functor,
void* context);
template<typename DexDebugNewPosition>
- bool DecodeDebugPositionInfo(const CodeItem* code_item,
- uint32_t debug_info_offset,
+ bool DecodeDebugPositionInfo(uint32_t debug_info_offset,
DexDebugNewPosition position_functor,
void* context) const;
diff --git a/runtime/dex_file_annotations.cc b/runtime/dex_file_annotations.cc
index eaf31f308f..72b18fb420 100644
--- a/runtime/dex_file_annotations.cc
+++ b/runtime/dex_file_annotations.cc
@@ -343,8 +343,7 @@ mirror::Object* ProcessEncodedAnnotation(const ClassData& klass, const uint8_t**
StackHandleScope<4> hs(self);
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
Handle<mirror::Class> annotation_class(hs.NewHandle(
- class_linker->ResolveType(klass.GetDexFile(),
- dex::TypeIndex(type_index),
+ class_linker->ResolveType(dex::TypeIndex(type_index),
hs.NewHandle(klass.GetDexCache()),
hs.NewHandle(klass.GetClassLoader()))));
if (annotation_class == nullptr) {
@@ -474,7 +473,6 @@ bool ProcessAnnotationValue(const ClassData& klass,
dex::TypeIndex type_index(index);
StackHandleScope<2> hs(self);
element_object = Runtime::Current()->GetClassLinker()->ResolveType(
- klass.GetDexFile(),
type_index,
hs.NewHandle(klass.GetDexCache()),
hs.NewHandle(klass.GetClassLoader()));
@@ -501,7 +499,6 @@ bool ProcessAnnotationValue(const ClassData& klass,
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
StackHandleScope<2> hs(self);
ArtMethod* method = class_linker->ResolveMethodWithoutInvokeType(
- klass.GetDexFile(),
index,
hs.NewHandle(klass.GetDexCache()),
hs.NewHandle(klass.GetClassLoader()));
@@ -783,7 +780,6 @@ const DexFile::AnnotationItem* GetAnnotationItemFromAnnotationSet(
Thread* self = Thread::Current();
StackHandleScope<2> hs(self);
ObjPtr<mirror::Class> resolved_class = class_linker->ResolveType(
- klass.GetDexFile(),
dex::TypeIndex(type_index),
hs.NewHandle(klass.GetDexCache()),
hs.NewHandle(klass.GetClassLoader()));
@@ -1398,7 +1394,6 @@ mirror::Class* GetEnclosingClass(Handle<mirror::Class> klass) {
}
StackHandleScope<2> hs(Thread::Current());
ArtMethod* method = Runtime::Current()->GetClassLinker()->ResolveMethodWithoutInvokeType(
- data.GetDexFile(),
annotation_value.value_.GetI(),
hs.NewHandle(data.GetDexCache()),
hs.NewHandle(data.GetClassLoader()));
@@ -1564,14 +1559,12 @@ int32_t GetLineNumFromPC(const DexFile* dex_file, ArtMethod* method, uint32_t re
return -2;
}
- const DexFile::CodeItem* code_item = dex_file->GetCodeItem(method->GetCodeItemOffset());
- DCHECK(code_item != nullptr) << method->PrettyMethod() << " " << dex_file->GetLocation();
+ CodeItemDebugInfoAccessor accessor(method);
+ DCHECK(accessor.HasCodeItem()) << method->PrettyMethod() << " " << dex_file->GetLocation();
// A method with no line number info should return -1
DexFile::LineNumFromPcContext context(rel_pc, -1);
- uint32_t debug_info_offset = OatFile::GetDebugInfoOffset(*dex_file, code_item);
- dex_file->DecodeDebugPositionInfo(
- code_item, debug_info_offset, DexFile::LineNumForPcCb, &context);
+ dex_file->DecodeDebugPositionInfo(accessor.DebugInfoOffset(), DexFile::LineNumForPcCb, &context);
return context.line_num_;
}
@@ -1596,8 +1589,7 @@ void RuntimeEncodedStaticFieldValueIterator::ReadValueToField(ArtField* field) c
break;
}
case kType: {
- ObjPtr<mirror::Class> resolved = linker_->ResolveType(dex_file_,
- dex::TypeIndex(jval_.i),
+ ObjPtr<mirror::Class> resolved = linker_->ResolveType(dex::TypeIndex(jval_.i),
dex_cache_,
class_loader_);
field->SetObject<kTransactionActive>(field->GetDeclaringClass(), resolved);
diff --git a/runtime/dex_file_test.cc b/runtime/dex_file_test.cc
index 14c36b4538..69055041e5 100644
--- a/runtime/dex_file_test.cc
+++ b/runtime/dex_file_test.cc
@@ -731,7 +731,14 @@ TEST_F(DexFileTest, OpenDexDebugInfoLocalNullType) {
const DexFile::ClassDef& class_def = raw->GetClassDef(0);
const DexFile::CodeItem* code_item = raw->GetCodeItem(raw->FindCodeItemOffset(class_def, 1));
uint32_t debug_info_offset = raw->GetDebugInfoOffset(code_item);
- ASSERT_TRUE(raw->DecodeDebugLocalInfo(code_item, debug_info_offset, true, 1, Callback, nullptr));
+ ASSERT_TRUE(raw->DecodeDebugLocalInfo(code_item->registers_size_,
+ code_item->ins_size_,
+ code_item->insns_size_in_code_units_,
+ debug_info_offset,
+ true,
+ 1,
+ Callback,
+ nullptr));
}
} // namespace art
diff --git a/runtime/entrypoints/entrypoint_utils-inl.h b/runtime/entrypoints/entrypoint_utils-inl.h
index fa3c027db8..9e5085067c 100644
--- a/runtime/entrypoints/entrypoint_utils-inl.h
+++ b/runtime/entrypoints/entrypoint_utils-inl.h
@@ -682,7 +682,7 @@ inline ArtMethod* FindMethodFast(uint32_t method_idx,
} else if (type == kSuper) {
// TODO This lookup is rather slow.
dex::TypeIndex method_type_idx = dex_cache->GetDexFile()->GetMethodId(method_idx).class_idx_;
- ObjPtr<mirror::Class> method_reference_class = ClassLinker::LookupResolvedType(
+ ObjPtr<mirror::Class> method_reference_class = linker->LookupResolvedType(
method_type_idx, dex_cache, referrer->GetClassLoader());
if (method_reference_class == nullptr) {
// Need to do full type resolution...
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index 0a76cddf5e..ca5b79921c 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -1250,17 +1250,8 @@ extern "C" const void* artQuickResolutionTrampoline(
} else {
DCHECK_EQ(invoke_type, kSuper);
CHECK(caller != nullptr) << invoke_type;
- StackHandleScope<2> hs(self);
- Handle<mirror::DexCache> dex_cache(
- hs.NewHandle(caller->GetDeclaringClass()->GetDexCache()));
- Handle<mirror::ClassLoader> class_loader(
- hs.NewHandle(caller->GetDeclaringClass()->GetClassLoader()));
- // TODO Maybe put this into a mirror::Class function.
ObjPtr<mirror::Class> ref_class = linker->LookupResolvedType(
- *dex_cache->GetDexFile(),
- dex_cache->GetDexFile()->GetMethodId(called_method.index).class_idx_,
- dex_cache.Get(),
- class_loader.Get());
+ caller->GetDexFile()->GetMethodId(called_method.index).class_idx_, caller);
if (ref_class->IsInterface()) {
called = ref_class->FindVirtualMethodForInterfaceSuper(called, kRuntimePointerSize);
} else {
@@ -2580,9 +2571,8 @@ extern "C" uintptr_t artInvokePolymorphic(
const Instruction& inst = code->InstructionAt(dex_pc);
DCHECK(inst.Opcode() == Instruction::INVOKE_POLYMORPHIC ||
inst.Opcode() == Instruction::INVOKE_POLYMORPHIC_RANGE);
- const DexFile* dex_file = caller_method->GetDexFile();
const uint32_t proto_idx = inst.VRegH();
- const char* shorty = dex_file->GetShorty(proto_idx);
+ const char* shorty = caller_method->GetDexFile()->GetShorty(proto_idx);
const size_t shorty_length = strlen(shorty);
static const bool kMethodIsStatic = false; // invoke() and invokeExact() are not static.
RememberForGcArgumentVisitor gc_visitor(sp, kMethodIsStatic, shorty, shorty_length, &soa);
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index 74813b4dd1..bcfc68c4a6 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -1587,7 +1587,9 @@ std::unique_ptr<ImageSpace> ImageSpace::CreateBootImage(const char* image_locati
if (!Runtime::Current()->IsImageDex2OatEnabled()) {
local_error_msg = "Patching disabled.";
} else if (secondary_image) {
- local_error_msg = "Cannot patch a secondary image.";
+ // We really want a working image. Prune and restart.
+ PruneDalvikCache(image_isa);
+ _exit(1);
} else if (ImageCreationAllowed(is_global_cache, image_isa, &local_error_msg)) {
bool patch_success =
RelocateImage(image_location, cache_filename.c_str(), image_isa, &local_error_msg);
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index 4d7a576c06..122d1a816b 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -1143,8 +1143,7 @@ static ObjPtr<mirror::CallSite> InvokeBootstrapMethod(Thread* self,
}
case EncodedArrayValueIterator::ValueType::kType: {
dex::TypeIndex idx(static_cast<uint32_t>(jvalue.i));
- ObjPtr<mirror::Class> ref =
- class_linker->ResolveType(*dex_file, idx, dex_cache, class_loader);
+ ObjPtr<mirror::Class> ref = class_linker->ResolveType(idx, dex_cache, class_loader);
if (ref.IsNull()) {
DCHECK(self->IsExceptionPending());
return nullptr;
diff --git a/runtime/jit/jit.cc b/runtime/jit/jit.cc
index 783d05df34..278bc57412 100644
--- a/runtime/jit/jit.cc
+++ b/runtime/jit/jit.cc
@@ -648,6 +648,10 @@ void Jit::AddSamples(Thread* self, ArtMethod* method, uint16_t count, bool with_
// We do not want to compile such methods.
return;
}
+ if (hot_method_threshold_ == 0) {
+ // Tests might request JIT on first use (compiled synchronously in the interpreter).
+ return;
+ }
DCHECK(thread_pool_ != nullptr);
DCHECK_GT(warm_method_threshold_, 0);
DCHECK_GT(hot_method_threshold_, warm_method_threshold_);
diff --git a/runtime/jni_internal_test.cc b/runtime/jni_internal_test.cc
index 1ecfe7cb76..efeff0a378 100644
--- a/runtime/jni_internal_test.cc
+++ b/runtime/jni_internal_test.cc
@@ -1783,66 +1783,115 @@ TEST_F(JniInternalTest, GetObjectArrayElement_SetObjectArrayElement) {
EXPECT_TRUE(vm_->SetCheckJniEnabled(old_check_jni)); \
} while (false)
+#define TEST_PRIMITIVE_FIELD_FOR_CLASS(cname) \
+ do { \
+ Thread::Current()->TransitionFromSuspendedToRunnable(); \
+ LoadDex("AllFields"); \
+ bool started = runtime_->Start(); \
+ ASSERT_TRUE(started); \
+ jclass c = env_->FindClass(cname); \
+ ASSERT_NE(c, nullptr); \
+ jobject o = env_->AllocObject(c); \
+ ASSERT_NE(o, nullptr); \
+ \
+ EXPECT_STATIC_PRIMITIVE_FIELD(EXPECT_EQ, Boolean, "sZ", "Z", JNI_TRUE, JNI_FALSE); \
+ EXPECT_STATIC_PRIMITIVE_FIELD(EXPECT_EQ, Byte, "sB", "B", 1, 2); \
+ EXPECT_STATIC_PRIMITIVE_FIELD(EXPECT_EQ, Char, "sC", "C", 'a', 'b'); \
+ EXPECT_STATIC_PRIMITIVE_FIELD(EXPECT_DOUBLE_EQ, Double, "sD", "D", 1.0, 2.0); \
+ EXPECT_STATIC_PRIMITIVE_FIELD(EXPECT_FLOAT_EQ, Float, "sF", "F", 1.0, 2.0); \
+ EXPECT_STATIC_PRIMITIVE_FIELD(EXPECT_EQ, Int, "sI", "I", 1, 2); \
+ EXPECT_STATIC_PRIMITIVE_FIELD(EXPECT_EQ, Long, "sJ", "J", 1, 2); \
+ EXPECT_STATIC_PRIMITIVE_FIELD(EXPECT_EQ, Short, "sS", "S", 1, 2); \
+ \
+ EXPECT_PRIMITIVE_FIELD(EXPECT_EQ, o, Boolean, "iZ", "Z", JNI_TRUE, JNI_FALSE); \
+ EXPECT_PRIMITIVE_FIELD(EXPECT_EQ, o, Byte, "iB", "B", 1, 2); \
+ EXPECT_PRIMITIVE_FIELD(EXPECT_EQ, o, Char, "iC", "C", 'a', 'b'); \
+ EXPECT_PRIMITIVE_FIELD(EXPECT_DOUBLE_EQ, o, Double, "iD", "D", 1.0, 2.0); \
+ EXPECT_PRIMITIVE_FIELD(EXPECT_FLOAT_EQ, o, Float, "iF", "F", 1.0, 2.0); \
+ EXPECT_PRIMITIVE_FIELD(EXPECT_EQ, o, Int, "iI", "I", 1, 2); \
+ EXPECT_PRIMITIVE_FIELD(EXPECT_EQ, o, Long, "iJ", "J", 1, 2); \
+ EXPECT_PRIMITIVE_FIELD(EXPECT_EQ, o, Short, "iS", "S", 1, 2); \
+ } while (false)
TEST_F(JniInternalTest, GetPrimitiveField_SetPrimitiveField) {
+ TEST_PRIMITIVE_FIELD_FOR_CLASS("AllFields");
+}
+
+TEST_F(JniInternalTest, GetPrimitiveField_SetPrimitiveField_Subclass) {
+ TEST_PRIMITIVE_FIELD_FOR_CLASS("AllFieldsSub");
+}
+
+#define EXPECT_UNRELATED_FIELD_FAILURE(type, field_name, sig, value1) \
+ do { \
+ jfieldID fid = env_->GetStaticFieldID(c, field_name, sig); \
+ EXPECT_NE(fid, nullptr); \
+ CheckJniAbortCatcher jni_abort_catcher; \
+ env_->Get ## type ## Field(uc, fid); \
+ jni_abort_catcher.Check("not valid for an object of class"); \
+ env_->Set ## type ## Field(uc, fid, value1); \
+ jni_abort_catcher.Check("not valid for an object of class"); \
+ } while (false)
+
+TEST_F(JniInternalTest, GetField_SetField_unrelated) {
Thread::Current()->TransitionFromSuspendedToRunnable();
LoadDex("AllFields");
bool started = runtime_->Start();
ASSERT_TRUE(started);
-
jclass c = env_->FindClass("AllFields");
ASSERT_NE(c, nullptr);
- jobject o = env_->AllocObject(c);
- ASSERT_NE(o, nullptr);
-
- EXPECT_STATIC_PRIMITIVE_FIELD(EXPECT_EQ, Boolean, "sZ", "Z", JNI_TRUE, JNI_FALSE);
- EXPECT_STATIC_PRIMITIVE_FIELD(EXPECT_EQ, Byte, "sB", "B", 1, 2);
- EXPECT_STATIC_PRIMITIVE_FIELD(EXPECT_EQ, Char, "sC", "C", 'a', 'b');
- EXPECT_STATIC_PRIMITIVE_FIELD(EXPECT_DOUBLE_EQ, Double, "sD", "D", 1.0, 2.0);
- EXPECT_STATIC_PRIMITIVE_FIELD(EXPECT_FLOAT_EQ, Float, "sF", "F", 1.0, 2.0);
- EXPECT_STATIC_PRIMITIVE_FIELD(EXPECT_EQ, Int, "sI", "I", 1, 2);
- EXPECT_STATIC_PRIMITIVE_FIELD(EXPECT_EQ, Long, "sJ", "J", 1, 2);
- EXPECT_STATIC_PRIMITIVE_FIELD(EXPECT_EQ, Short, "sS", "S", 1, 2);
-
- EXPECT_PRIMITIVE_FIELD(EXPECT_EQ, o, Boolean, "iZ", "Z", JNI_TRUE, JNI_FALSE);
- EXPECT_PRIMITIVE_FIELD(EXPECT_EQ, o, Byte, "iB", "B", 1, 2);
- EXPECT_PRIMITIVE_FIELD(EXPECT_EQ, o, Char, "iC", "C", 'a', 'b');
- EXPECT_PRIMITIVE_FIELD(EXPECT_DOUBLE_EQ, o, Double, "iD", "D", 1.0, 2.0);
- EXPECT_PRIMITIVE_FIELD(EXPECT_FLOAT_EQ, o, Float, "iF", "F", 1.0, 2.0);
- EXPECT_PRIMITIVE_FIELD(EXPECT_EQ, o, Int, "iI", "I", 1, 2);
- EXPECT_PRIMITIVE_FIELD(EXPECT_EQ, o, Long, "iJ", "J", 1, 2);
- EXPECT_PRIMITIVE_FIELD(EXPECT_EQ, o, Short, "iS", "S", 1, 2);
+ jclass uc = env_->FindClass("AllFieldsUnrelated");
+ ASSERT_NE(uc, nullptr);
+ bool old_check_jni = vm_->SetCheckJniEnabled(true);
+ EXPECT_UNRELATED_FIELD_FAILURE(Boolean, "sZ", "Z", JNI_TRUE);
+ EXPECT_UNRELATED_FIELD_FAILURE(Byte, "sB", "B", 1);
+ EXPECT_UNRELATED_FIELD_FAILURE(Char, "sC", "C", 'a');
+ EXPECT_UNRELATED_FIELD_FAILURE(Double, "sD", "D", 1.0);
+ EXPECT_UNRELATED_FIELD_FAILURE(Float, "sF", "F", 1.0);
+ EXPECT_UNRELATED_FIELD_FAILURE(Int, "sI", "I", 1);
+ EXPECT_UNRELATED_FIELD_FAILURE(Long, "sJ", "J", 1);
+ EXPECT_UNRELATED_FIELD_FAILURE(Short, "sS", "S", 1);
+ EXPECT_UNRELATED_FIELD_FAILURE(Object, "sObject", "Ljava/lang/Object;", c);
+ EXPECT_TRUE(vm_->SetCheckJniEnabled(old_check_jni));
}
-TEST_F(JniInternalTest, GetObjectField_SetObjectField) {
- Thread::Current()->TransitionFromSuspendedToRunnable();
- LoadDex("AllFields");
- runtime_->Start();
+#define TEST_OBJECT_FIELD_FOR_CLASS(cname) \
+ do { \
+ Thread::Current()->TransitionFromSuspendedToRunnable(); \
+ LoadDex("AllFields"); \
+ runtime_->Start(); \
+ \
+ jclass c = env_->FindClass(cname); \
+ ASSERT_NE(c, nullptr); \
+ jobject o = env_->AllocObject(c); \
+ ASSERT_NE(o, nullptr); \
+ \
+ jstring s1 = env_->NewStringUTF("hello"); \
+ ASSERT_NE(s1, nullptr); \
+ jstring s2 = env_->NewStringUTF("world"); \
+ ASSERT_NE(s2, nullptr); \
+ \
+ jfieldID s_fid = env_->GetStaticFieldID(c, "sObject", "Ljava/lang/Object;"); \
+ ASSERT_NE(s_fid, nullptr); \
+ jfieldID i_fid = env_->GetFieldID(c, "iObject", "Ljava/lang/Object;"); \
+ ASSERT_NE(i_fid, nullptr); \
+ \
+ env_->SetStaticObjectField(c, s_fid, s1); \
+ ASSERT_TRUE(env_->IsSameObject(s1, env_->GetStaticObjectField(c, s_fid))); \
+ env_->SetStaticObjectField(c, s_fid, s2); \
+ ASSERT_TRUE(env_->IsSameObject(s2, env_->GetStaticObjectField(c, s_fid))); \
+ \
+ env_->SetObjectField(o, i_fid, s1); \
+ ASSERT_TRUE(env_->IsSameObject(s1, env_->GetObjectField(o, i_fid))); \
+ env_->SetObjectField(o, i_fid, s2); \
+ ASSERT_TRUE(env_->IsSameObject(s2, env_->GetObjectField(o, i_fid))); \
+ } while (false)
- jclass c = env_->FindClass("AllFields");
- ASSERT_NE(c, nullptr);
- jobject o = env_->AllocObject(c);
- ASSERT_NE(o, nullptr);
+TEST_F(JniInternalTest, GetObjectField_SetObjectField) {
+ TEST_OBJECT_FIELD_FOR_CLASS("AllFields");
+}
- jstring s1 = env_->NewStringUTF("hello");
- ASSERT_NE(s1, nullptr);
- jstring s2 = env_->NewStringUTF("world");
- ASSERT_NE(s2, nullptr);
-
- jfieldID s_fid = env_->GetStaticFieldID(c, "sObject", "Ljava/lang/Object;");
- ASSERT_NE(s_fid, nullptr);
- jfieldID i_fid = env_->GetFieldID(c, "iObject", "Ljava/lang/Object;");
- ASSERT_NE(i_fid, nullptr);
-
- env_->SetStaticObjectField(c, s_fid, s1);
- ASSERT_TRUE(env_->IsSameObject(s1, env_->GetStaticObjectField(c, s_fid)));
- env_->SetStaticObjectField(c, s_fid, s2);
- ASSERT_TRUE(env_->IsSameObject(s2, env_->GetStaticObjectField(c, s_fid)));
-
- env_->SetObjectField(o, i_fid, s1);
- ASSERT_TRUE(env_->IsSameObject(s1, env_->GetObjectField(o, i_fid)));
- env_->SetObjectField(o, i_fid, s2);
- ASSERT_TRUE(env_->IsSameObject(s2, env_->GetObjectField(o, i_fid)));
+TEST_F(JniInternalTest, GetObjectField_SetObjectField_subclass) {
+ TEST_OBJECT_FIELD_FOR_CLASS("AllFieldsSub");
}
TEST_F(JniInternalTest, NewLocalRef_nullptr) {
diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h
index eb54f7fb1f..b4f5d81067 100644
--- a/runtime/mirror/class-inl.h
+++ b/runtime/mirror/class-inl.h
@@ -440,7 +440,6 @@ inline bool Class::ResolvedFieldAccessTest(ObjPtr<Class> access_to,
// cache. Use LookupResolveType here to search the class table if it is not in the dex cache.
// should be no thread suspension due to the class being resolved.
ObjPtr<Class> dex_access_to = Runtime::Current()->GetClassLinker()->LookupResolvedType(
- *dex_cache->GetDexFile(),
class_idx,
dex_cache,
access_to->GetClassLoader());
@@ -477,7 +476,6 @@ inline bool Class::ResolvedMethodAccessTest(ObjPtr<Class> access_to,
// The referenced class has already been resolved with the method, but may not be in the dex
// cache.
ObjPtr<Class> dex_access_to = Runtime::Current()->GetClassLinker()->LookupResolvedType(
- *dex_cache->GetDexFile(),
class_idx,
dex_cache,
access_to->GetClassLoader());
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc
index a0a2f46433..e0a341da67 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -1035,7 +1035,7 @@ ObjPtr<Class> Class::GetDirectInterface(Thread* self, ObjPtr<Class> klass, uint3
return interfaces->Get(idx);
} else {
dex::TypeIndex type_idx = klass->GetDirectInterfaceTypeIdx(idx);
- ObjPtr<Class> interface = ClassLinker::LookupResolvedType(
+ ObjPtr<Class> interface = Runtime::Current()->GetClassLinker()->LookupResolvedType(
type_idx, klass->GetDexCache(), klass->GetClassLoader());
return interface;
}
@@ -1047,9 +1047,7 @@ ObjPtr<Class> Class::ResolveDirectInterface(Thread* self, Handle<Class> klass, u
DCHECK(!klass->IsArrayClass());
DCHECK(!klass->IsProxyClass());
dex::TypeIndex type_idx = klass->GetDirectInterfaceTypeIdx(idx);
- interface = Runtime::Current()->GetClassLinker()->ResolveType(klass->GetDexFile(),
- type_idx,
- klass.Get());
+ interface = Runtime::Current()->GetClassLinker()->ResolveType(type_idx, klass.Get());
CHECK(interface != nullptr || self->IsExceptionPending());
}
return interface;
diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc
index 2d1f886896..1b5c535c87 100644
--- a/runtime/native/dalvik_system_VMRuntime.cc
+++ b/runtime/native/dalvik_system_VMRuntime.cc
@@ -375,8 +375,8 @@ static void PreloadDexCachesResolveField(ObjPtr<mirror::DexCache> dex_cache,
}
const DexFile* dex_file = dex_cache->GetDexFile();
const DexFile::FieldId& field_id = dex_file->GetFieldId(field_idx);
- ObjPtr<mirror::Class> klass =
- ClassLinker::LookupResolvedType(field_id.class_idx_, dex_cache, nullptr);
+ ObjPtr<mirror::Class> klass = Runtime::Current()->GetClassLinker()->LookupResolvedType(
+ field_id.class_idx_, dex_cache, /* class_loader */ nullptr);
if (klass == nullptr) {
return;
}
@@ -401,8 +401,8 @@ static void PreloadDexCachesResolveMethod(ObjPtr<mirror::DexCache> dex_cache, ui
}
const DexFile* dex_file = dex_cache->GetDexFile();
const DexFile::MethodId& method_id = dex_file->GetMethodId(method_idx);
- ObjPtr<mirror::Class> klass =
- ClassLinker::LookupResolvedType(method_id.class_idx_, dex_cache, nullptr);
+ ObjPtr<mirror::Class> klass = Runtime::Current()->GetClassLinker()->LookupResolvedType(
+ method_id.class_idx_, dex_cache, /* class_loader */ nullptr);
if (klass == nullptr) {
return;
}
diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc
index 9359ffc7fd..da5cee1ddc 100644
--- a/runtime/native/java_lang_Class.cc
+++ b/runtime/native/java_lang_Class.cc
@@ -146,11 +146,11 @@ static jobjectArray Class_getInterfacesInternal(JNIEnv* env, jobject javaThis) {
// with kActiveTransaction == false.
DCHECK(!Runtime::Current()->IsActiveTransaction());
+ ClassLinker* linker = Runtime::Current()->GetClassLinker();
MutableHandle<mirror::Class> interface(hs.NewHandle<mirror::Class>(nullptr));
for (uint32_t i = 0; i < num_ifaces; ++i) {
const dex::TypeIndex type_idx = iface_list->GetTypeItem(i).type_idx_;
- interface.Assign(ClassLinker::LookupResolvedType(
- type_idx, klass->GetDexCache(), klass->GetClassLoader()));
+ interface.Assign(linker->LookupResolvedType(type_idx, klass.Get()));
ifaces->SetWithoutChecks<false>(i, interface.Get());
}
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 7239ad3213..1cdeb7c77c 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -297,6 +297,7 @@ Runtime::~Runtime() {
}
if (dump_gc_performance_on_shutdown_) {
+ ScopedLogSeverity sls(LogSeverity::INFO);
// This can't be called from the Heap destructor below because it
// could call RosAlloc::InspectAll() which needs the thread_list
// to be still alive.
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 24f83b881d..4ff49edb90 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -230,7 +230,7 @@ MethodVerifier::FailureData MethodVerifier::VerifyMethods(Thread* self,
previous_method_idx = method_idx;
InvokeType type = it->GetMethodInvokeType(class_def);
ArtMethod* method = linker->ResolveMethod<ClassLinker::ResolveMode::kNoChecks>(
- *dex_file, method_idx, dex_cache, class_loader, nullptr, type);
+ method_idx, dex_cache, class_loader, /* referrer */ nullptr, type);
if (method == nullptr) {
DCHECK(self->IsExceptionPending());
// We couldn't resolve the method, but continue regardless.
@@ -1077,9 +1077,8 @@ bool MethodVerifier::ScanTryCatchBlocks() {
// Ensure exception types are resolved so that they don't need resolution to be delivered,
// unresolved exception types will be ignored by exception delivery
if (iterator.GetHandlerTypeIndex().IsValid()) {
- ObjPtr<mirror::Class> exception_type = linker->ResolveType(*dex_file_,
- iterator.GetHandlerTypeIndex(),
- dex_cache_, class_loader_);
+ ObjPtr<mirror::Class> exception_type =
+ linker->ResolveType(iterator.GetHandlerTypeIndex(), dex_cache_, class_loader_);
if (exception_type == nullptr) {
DCHECK(self_->IsExceptionPending());
self_->ClearException();
@@ -2434,8 +2433,8 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
const RegType& res_type = ResolveClass<CheckAccess::kYes>(type_idx);
if (res_type.IsConflict()) {
// If this is a primitive type, fail HARD.
- ObjPtr<mirror::Class> klass =
- ClassLinker::LookupResolvedType(type_idx, dex_cache_.Get(), class_loader_.Get());
+ ObjPtr<mirror::Class> klass = Runtime::Current()->GetClassLinker()->LookupResolvedType(
+ type_idx, dex_cache_.Get(), class_loader_.Get());
if (klass != nullptr && klass->IsPrimitive()) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "using primitive type "
<< dex_file_->StringByTypeIdx(type_idx) << " in instanceof in "
@@ -3643,7 +3642,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
} else {
// It is also a catch-all if it is java.lang.Throwable.
ObjPtr<mirror::Class> klass =
- linker->ResolveType(*dex_file_, handler_type_idx, dex_cache_, class_loader_);
+ linker->ResolveType(handler_type_idx, dex_cache_, class_loader_);
if (klass != nullptr) {
if (klass == mirror::Throwable::GetJavaLangThrowable()) {
has_catch_all_handler = true;
@@ -3767,10 +3766,10 @@ inline bool MethodVerifier::IsInstantiableOrPrimitive(ObjPtr<mirror::Class> klas
template <MethodVerifier::CheckAccess C>
const RegType& MethodVerifier::ResolveClass(dex::TypeIndex class_idx) {
+ ClassLinker* linker = Runtime::Current()->GetClassLinker();
ObjPtr<mirror::Class> klass = can_load_classes_
- ? Runtime::Current()->GetClassLinker()->ResolveType(
- *dex_file_, class_idx, dex_cache_, class_loader_)
- : ClassLinker::LookupResolvedType(class_idx, dex_cache_.Get(), class_loader_.Get());
+ ? linker->ResolveType(class_idx, dex_cache_, class_loader_)
+ : linker->LookupResolvedType(class_idx, dex_cache_.Get(), class_loader_.Get());
if (can_load_classes_ && klass == nullptr) {
DCHECK(self_->IsExceptionPending());
self_->ClearException();
diff --git a/test/004-JniTest/expected.txt b/test/004-JniTest/expected.txt
index 1d05160883..b09b9a22eb 100644
--- a/test/004-JniTest/expected.txt
+++ b/test/004-JniTest/expected.txt
@@ -1,4 +1,5 @@
JNI_OnLoad called
+ABC.XYZ = 12, GetStaticIntField(DEF.class, 'XYZ') = 12
Super.<init>
Super.<init>
Subclass.<init>
diff --git a/test/004-JniTest/jni_test.cc b/test/004-JniTest/jni_test.cc
index 4561895509..33a8f5bba2 100644
--- a/test/004-JniTest/jni_test.cc
+++ b/test/004-JniTest/jni_test.cc
@@ -90,6 +90,14 @@ static void testFindClassOnAttachedNativeThread(JNIEnv* env) {
CHECK(!env->ExceptionCheck());
}
+extern "C" JNIEXPORT jint JNICALL Java_Main_getFieldSubclass(JNIEnv* env,
+ jclass,
+ jobject f_obj,
+ jclass sub) {
+ jfieldID f = env->FromReflectedField(f_obj);
+ return env->GetStaticIntField(sub, f);
+}
+
// http://b/10994325
extern "C" JNIEXPORT void JNICALL Java_Main_testFindClassOnAttachedNativeThread(JNIEnv*, jclass) {
PthreadHelper(&testFindClassOnAttachedNativeThread);
diff --git a/test/004-JniTest/src/Main.java b/test/004-JniTest/src/Main.java
index 871107c56b..f94dcf6c70 100644
--- a/test/004-JniTest/src/Main.java
+++ b/test/004-JniTest/src/Main.java
@@ -18,6 +18,7 @@ import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
+import java.lang.reflect.Field;
import java.lang.reflect.Proxy;
import java.util.regex.Pattern;
@@ -32,6 +33,7 @@ public class Main {
throw new RuntimeException("Slow-debug flags unexpectedly off.");
}
+ testFieldSubclass();
testFindClassOnAttachedNativeThread();
testFindFieldOnAttachedNativeThread();
testReflectFieldGetFromAttachedNativeThreadNative();
@@ -65,6 +67,19 @@ public class Main {
testDoubleLoad(args[0]);
}
+ static class ABC { public static int XYZ = 12; }
+ static class DEF extends ABC {}
+ public static void testFieldSubclass() {
+ try {
+ System.out.println("ABC.XYZ = " + ABC.XYZ + ", GetStaticIntField(DEF.class, 'XYZ') = " +
+ getFieldSubclass(ABC.class.getDeclaredField("XYZ"), DEF.class));
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to test get static field on a subclass", e);
+ }
+ }
+
+ public static native int getFieldSubclass(Field f, Class sub);
+
private static native boolean registerNativesJniTest();
private static native void testCallDefaultMethods();
diff --git a/test/137-cfi/run b/test/137-cfi/run
index ebc729bc74..adea71a07f 100755
--- a/test/137-cfi/run
+++ b/test/137-cfi/run
@@ -16,10 +16,15 @@
# Test with full DWARF debugging information.
# Check full signatures of methods.
+# The option jitthreshold:0 ensures that if we run the test in JIT mode,
+# there will be JITed frames on the callstack (it synchronously JITs on first use).
${RUN} "$@" -Xcompiler-option --generate-debug-info \
+ --runtime-option -Xjitthreshold:0 \
--args --full-signatures --args --test-local --args --test-remote
# Test with minimal compressed debugging information.
# Check only method names (parameters are omitted to save space).
# Check only remote unwinding since decompression is disabled in local unwinds (b/27391690).
-${RUN} "$@" -Xcompiler-option --generate-mini-debug-info --args --test-remote
+${RUN} "$@" -Xcompiler-option --generate-mini-debug-info \
+ --runtime-option -Xjitthreshold:0 \
+ --args --test-remote
diff --git a/test/1940-ddms-ext/check b/test/1940-ddms-ext/check
new file mode 100755
index 0000000000..d2c03841fc
--- /dev/null
+++ b/test/1940-ddms-ext/check
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# Copyright (C) 2017 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.
+
+# Need to pull out the describeException ouput since that won't be there on
+# device.
+sed -e '/\t.*$/d' "$2" | sed -e '/java.lang.ArrayIndexOutOfBoundsException:.*$/d' > "$2.tmp"
+
+./default-check "$1" "$2.tmp"
diff --git a/test/1940-ddms-ext/expected.txt b/test/1940-ddms-ext/expected.txt
index 62d3b7bd4c..1a457a01a5 100644
--- a/test/1940-ddms-ext/expected.txt
+++ b/test/1940-ddms-ext/expected.txt
@@ -3,8 +3,19 @@ MyDdmHandler: Chunk received: Chunk(Type: 0xDEADBEEF, Len: 8, data: [1, 2, 3, 4,
MyDdmHandler: Putting value 0x800025
MyDdmHandler: Chunk returned: Chunk(Type: 0xFADE7357, Len: 8, data: [0, 0, 0, 0, 0, -128, 0, 37])
JVMTI returned chunk: Chunk(Type: 0xFADE7357, Len: 8, data: [0, 0, 0, 0, 0, -128, 0, 37])
+Sending empty data array
+MyDdmHandler: Chunk received: Chunk(Type: 0xDEADBEEF, Len: 0, data: [])
+MyDdmHandler: Putting value 0x1
+MyDdmHandler: Chunk returned: Chunk(Type: 0xFADE7357, Len: 8, data: [0, 0, 0, 0, 0, 0, 0, 1])
+JVMTI returned chunk: Chunk(Type: 0xFADE7357, Len: 8, data: [0, 0, 0, 0, 0, 0, 0, 1])
Sending chunk: Chunk(Type: 0xDEADBEEF, Len: 8, data: [9, 10, 11, 12, 13, 14, 15, 16])
Chunk published: Chunk(Type: 0xDEADBEEF, Len: 8, data: [9, 10, 11, 12, 13, 14, 15, 16])
+Sending data [1] to chunk handler -1412567295
+MyDdmHandler: Chunk received: Chunk(Type: 0xABCDEF01, Len: 1, data: [1])
+JVMTI returned chunk: Chunk(Type: 0xFADE7357, Len: 0, data: [])
+Sending data [1] to chunk handler 305419896
+MyDdmHandler: Chunk received: Chunk(Type: 0x12345678, Len: 1, data: [1])
+Got error: JVMTI_ERROR_INTERNAL
Saw expected thread events.
Expected chunk type published: 1213221190
Expected chunk type published: 1297109829
diff --git a/test/1940-ddms-ext/src-art/art/Test1940.java b/test/1940-ddms-ext/src-art/art/Test1940.java
index 9f79eaebba..226fe350bd 100644
--- a/test/1940-ddms-ext/src-art/art/Test1940.java
+++ b/test/1940-ddms-ext/src-art/art/Test1940.java
@@ -30,6 +30,8 @@ public class Test1940 {
public static final int DDMS_HEADER_LENGTH = 8;
public static final int MY_DDMS_TYPE = 0xDEADBEEF;
public static final int MY_DDMS_RESPONSE_TYPE = 0xFADE7357;
+ public static final int MY_EMPTY_DDMS_TYPE = 0xABCDEF01;
+ public static final int MY_INVALID_DDMS_TYPE = 0x12345678;
public static final boolean PRINT_ALL_CHUNKS = false;
@@ -58,19 +60,27 @@ public class Test1940 {
public void connected() {}
public void disconnected() {}
public Chunk handleChunk(Chunk req) {
- // For this test we will simply calculate the checksum
- checkEq(req.type, MY_DDMS_TYPE);
System.out.println("MyDdmHandler: Chunk received: " + printChunk(req));
- ByteBuffer b = ByteBuffer.wrap(new byte[8]);
- Adler32 a = new Adler32();
- a.update(req.data, req.offset, req.length);
- b.order(ByteOrder.BIG_ENDIAN);
- long val = a.getValue();
- b.putLong(val);
- System.out.printf("MyDdmHandler: Putting value 0x%X\n", val);
- Chunk ret = new Chunk(MY_DDMS_RESPONSE_TYPE, b.array(), 0, 8);
- System.out.println("MyDdmHandler: Chunk returned: " + printChunk(ret));
- return ret;
+ if (req.type == MY_DDMS_TYPE) {
+ // For this test we will simply calculate the checksum
+ ByteBuffer b = ByteBuffer.wrap(new byte[8]);
+ Adler32 a = new Adler32();
+ a.update(req.data, req.offset, req.length);
+ b.order(ByteOrder.BIG_ENDIAN);
+ long val = a.getValue();
+ b.putLong(val);
+ System.out.printf("MyDdmHandler: Putting value 0x%X\n", val);
+ Chunk ret = new Chunk(MY_DDMS_RESPONSE_TYPE, b.array(), 0, 8);
+ System.out.println("MyDdmHandler: Chunk returned: " + printChunk(ret));
+ return ret;
+ } else if (req.type == MY_EMPTY_DDMS_TYPE) {
+ return new Chunk(MY_DDMS_RESPONSE_TYPE, new byte[0], 0, 0);
+ } else if (req.type == MY_INVALID_DDMS_TYPE) {
+ // This is a very invalid chunk.
+ return new Chunk(MY_DDMS_RESPONSE_TYPE, new byte[] { 0 }, /*offset*/ 12, /*length*/ 55);
+ } else {
+ throw new TestError("Unknown ddm request type: " + req.type);
+ }
}
}
@@ -113,18 +123,42 @@ public class Test1940 {
Test1940.class.getDeclaredMethod("HandlePublish", Integer.TYPE, new byte[0].getClass()));
// Test sending chunk directly.
DdmServer.registerHandler(MY_DDMS_TYPE, SINGLE_HANDLER);
+ DdmServer.registerHandler(MY_EMPTY_DDMS_TYPE, SINGLE_HANDLER);
+ DdmServer.registerHandler(MY_INVALID_DDMS_TYPE, SINGLE_HANDLER);
DdmServer.registrationComplete();
byte[] data = new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
System.out.println("Sending data " + Arrays.toString(data));
Chunk res = processChunk(data);
System.out.println("JVMTI returned chunk: " + printChunk(res));
+ // Test sending an empty chunk.
+ System.out.println("Sending empty data array");
+ res = processChunk(new byte[0]);
+ System.out.println("JVMTI returned chunk: " + printChunk(res));
+
// Test sending chunk through DdmServer#sendChunk
Chunk c = new Chunk(
MY_DDMS_TYPE, new byte[] { 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10 }, 0, 8);
System.out.println("Sending chunk: " + printChunk(c));
DdmServer.sendChunk(c);
+ // Test getting back an empty chunk.
+ data = new byte[] { 0x1 };
+ System.out.println(
+ "Sending data " + Arrays.toString(data) + " to chunk handler " + MY_EMPTY_DDMS_TYPE);
+ res = processChunk(new Chunk(MY_EMPTY_DDMS_TYPE, data, 0, 1));
+ System.out.println("JVMTI returned chunk: " + printChunk(res));
+
+ // Test getting back an invalid chunk.
+ System.out.println(
+ "Sending data " + Arrays.toString(data) + " to chunk handler " + MY_INVALID_DDMS_TYPE);
+ try {
+ res = processChunk(new Chunk(MY_INVALID_DDMS_TYPE, data, 0, 1));
+ System.out.println("JVMTI returned chunk: " + printChunk(res));
+ } catch (RuntimeException e) {
+ System.out.println("Got error: " + e.getMessage());
+ }
+
// Test thread chunks are sent.
final boolean[] types_seen = new boolean[] { false, false, false };
CURRENT_HANDLER = (type, cdata) -> {
diff --git a/test/458-checker-instruct-simplification/src/Main.java b/test/458-checker-instruct-simplification/src/Main.java
index 7797f31867..ccaba61722 100644
--- a/test/458-checker-instruct-simplification/src/Main.java
+++ b/test/458-checker-instruct-simplification/src/Main.java
@@ -2602,6 +2602,124 @@ public class Main {
return (byte)((int)(((long)(b & 0xff)) & 255L));
}
+ /// CHECK-START: void Main.$noinline$testIfCondStaticEvaluation(int[], boolean) instruction_simplifier (before)
+ /// CHECK-DAG: <<Param:z\d+>> ParameterValue
+ /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0
+ /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1
+ /// CHECK-DAG: <<Cond0:z\d+>> Equal [<<Param>>,<<Const0>>]
+ /// CHECK-DAG: If [<<Cond0>>]
+ /// CHECK-DAG: <<Cond1:z\d+>> Equal [<<Param>>,<<Const0>>]
+ /// CHECK-DAG: If [<<Cond1>>]
+ /// CHECK-DAG: ArraySet [{{l\d+}},{{i\d+}},<<Const0>>]
+ /// CHECK-DAG: <<Cond2:z\d+>> Equal [<<Param>>,<<Const0>>]
+ /// CHECK-DAG: If [<<Cond2>>]
+ /// CHECK-DAG: ArraySet [{{l\d+}},{{i\d+}},<<Const1>>]
+ //
+ /// CHECK-NOT: If
+ /// CHECK-NOT: ArraySet
+
+ /// CHECK-START: void Main.$noinline$testIfCondStaticEvaluation(int[], boolean) instruction_simplifier (after)
+ /// CHECK-DAG: <<Param:z\d+>> ParameterValue
+ /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0
+ /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1
+ /// CHECK-DAG: If [<<Param>>]
+ /// CHECK-DAG: <<Cond1:z\d+>> Equal [<<Const1>>,<<Const0>>]
+ /// CHECK-DAG: If [<<Cond1>>]
+ /// CHECK-DAG: ArraySet [{{l\d+}},{{i\d+}},<<Const1>>]
+ /// CHECK-DAG: <<Cond2:z\d+>> Equal [<<Const0>>,<<Const0>>]
+ /// CHECK-DAG: If [<<Cond2>>]
+ /// CHECK-DAG: ArraySet [{{l\d+}},{{i\d+}},<<Const0>>]
+ //
+ /// CHECK-NOT: If
+ /// CHECK-NOT: ArraySet
+
+ /// CHECK-START: void Main.$noinline$testIfCondStaticEvaluation(int[], boolean) dead_code_elimination$after_inlining (after)
+ /// CHECK-DAG: <<Param:z\d+>> ParameterValue
+ /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1
+ /// CHECK-DAG: If [<<Param>>]
+ /// CHECK-DAG: ArraySet [{{l\d+}},{{i\d+}},<<Const1>>]
+ //
+ /// CHECK-NOT: IntConstant 0
+ /// CHECK-NOT: If [<<Param>>]
+ /// CHECK-NOT: ArraySet
+ private static void $noinline$testIfCondStaticEvaluation(int[] a, boolean f) {
+ if (f) {
+ if (f) {
+ a[0] = 1;
+ }
+ } else {
+ if (f) {
+ a[0] = 0;
+ }
+ }
+ }
+
+ /// CHECK-START: void Main.$noinline$testManualUnrollWithInvarExits(int[], boolean) instruction_simplifier (before)
+ /// CHECK-DAG: <<Param:z\d+>> ParameterValue loop:none
+ /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 loop:none
+ /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 loop:none
+ /// CHECK-DAG: <<Cond0:z\d+>> Equal [<<Param>>,<<Const0>>] loop:none
+ /// CHECK-DAG: If [<<Cond0>>] loop:none
+ /// CHECK-DAG: ArraySet [{{l\d+}},{{i\d+}},<<Const1>>] loop:none
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<LoopCheck:z\d+>> GreaterThanOrEqual loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: If [<<LoopCheck>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Cond1:z\d+>> NotEqual [<<Param>>,<<Const0>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: If [<<Cond1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: ArraySet [{{l\d+}},{{i\d+}},<<Const1>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-NOT: If
+ /// CHECK-NOT: ArraySet
+
+ /// CHECK-START: void Main.$noinline$testManualUnrollWithInvarExits(int[], boolean) instruction_simplifier (after)
+ /// CHECK-DAG: <<Param:z\d+>> ParameterValue loop:none
+ /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 loop:none
+ /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 loop:none
+ /// CHECK-DAG: If [<<Param>>] loop:none
+ /// CHECK-DAG: ArraySet [{{l\d+}},{{i\d+}},<<Const1>>] loop:none
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<LoopCheck:z\d+>> GreaterThanOrEqual loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: If [<<LoopCheck>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Cond1:z\d+>> NotEqual [<<Const0>>,<<Const0>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: If [<<Cond1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: ArraySet [{{l\d+}},{{i\d+}},<<Const1>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-NOT: If
+ /// CHECK-NOT: ArraySet
+
+ /// CHECK-START: void Main.$noinline$testManualUnrollWithInvarExits(int[], boolean) dead_code_elimination$after_inlining (after)
+ /// CHECK-DAG: <<Param:z\d+>> ParameterValue loop:none
+ /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 loop:none
+ /// CHECK-DAG: If [<<Param>>] loop:none
+ /// CHECK-DAG: ArraySet [{{l\d+}},{{i\d+}},<<Const1>>] loop:none
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<LoopCheck:z\d+>> GreaterThanOrEqual loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: If [<<LoopCheck>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: ArraySet [{{l\d+}},{{i\d+}},<<Const1>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-NOT: If
+ /// CHECK-NOT: ArraySet
+ private static void $noinline$testManualUnrollWithInvarExits(int[] a, boolean f) {
+ if (f) {
+ return;
+ }
+ a[0] = 1;
+ for (int i = 1; i < a.length; i++) {
+ if (f) {
+ return;
+ }
+ a[i] = 1;
+ }
+ }
+
+ public static final int LENGTH = 1024;
+
+ private static final void initArray(int[] a) {
+ for (int i = 0; i < a.length; i++) {
+ a[i] = 0;
+ }
+ }
+
public static void main(String[] args) {
int arg = 123456;
float floatArg = 123456.125f;
@@ -2845,6 +2963,26 @@ public class Main {
assertIntEquals(1, $noinline$bug68142795Boolean(true));
assertIntEquals(0x7f, $noinline$bug68142795Elaborate((byte) 0x7f));
assertIntEquals((byte) 0x80, $noinline$bug68142795Elaborate((byte) 0x80));
+
+ int[] array = new int[LENGTH];
+
+ array[0] = 0;
+ $noinline$testIfCondStaticEvaluation(array, true);
+ assertIntEquals(array[0], 1);
+ array[0] = 0;
+ $noinline$testIfCondStaticEvaluation(array, false);
+ assertIntEquals(array[0], 0);
+
+ initArray(array);
+ $noinline$testManualUnrollWithInvarExits(array, false);
+ for (int i = 0; i < array.length; i++) {
+ assertIntEquals(array[i], 1);
+ }
+ initArray(array);
+ $noinline$testManualUnrollWithInvarExits(array, true);
+ for (int i = 0; i < array.length; i++) {
+ assertIntEquals(array[i], 0);
+ }
}
private static boolean $inline$true() { return true; }
diff --git a/test/667-jit-jni-stub/src/Main.java b/test/667-jit-jni-stub/src/Main.java
index b867970eab..794308d6e1 100644
--- a/test/667-jit-jni-stub/src/Main.java
+++ b/test/667-jit-jni-stub/src/Main.java
@@ -135,13 +135,16 @@ public class Main {
int count = 0;
while (!hasJitCompiledEntrypoint(Main.class, "callThrough")) {
// If `call` is true, also exercise the `callThrough()` method to increase hotness.
- int limit = call ? 1 << Math.min(count, 12) : 0;
+ // Ramp-up the number of calls we do up to 1 << 12.
+ final int rampUpCutOff = 12;
+ int limit = call ? 1 << Math.min(count, rampUpCutOff) : 0;
for (int i = 0; i < limit; ++i) {
callThrough(Main.class, "doNothing");
}
try {
- // Sleep to give a chance for the JIT to compile `hasJit` stub.
- Thread.sleep(100);
+ // Sleep to give a chance for the JIT to compile `callThrough` stub.
+ // After the ramp-up phase, give the JIT even more time to compile.
+ Thread.sleep(count >= rampUpCutOff ? 200 : 100);
} catch (Exception e) {
// Ignore
}
diff --git a/test/706-checker-scheduler/src/Main.java b/test/706-checker-scheduler/src/Main.java
index d21596d4bc..25e4fad714 100644
--- a/test/706-checker-scheduler/src/Main.java
+++ b/test/706-checker-scheduler/src/Main.java
@@ -523,7 +523,71 @@ public class Main {
return res;
}
+ private static void expectEquals(int expected, int result) {
+ if (expected != result) {
+ throw new Error("Expected: " + expected + ", found: " + result);
+ }
+ }
+
+ private static final int ARRAY_SIZE = 32;
+
+ // Check that VecReplicateScalar is not reordered.
+ /// CHECK-START-ARM64: void Main.testVecReplicateScalar() scheduler (before)
+ /// CHECK: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK: NewArray loop:<<Loop>> outer_loop:none
+ /// CHECK: VecReplicateScalar loop:<<Loop>> outer_loop:none
+
+ /// CHECK-START-ARM64: void Main.testVecReplicateScalar() scheduler (after)
+ /// CHECK: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK: NewArray loop:<<Loop>> outer_loop:none
+ /// CHECK: VecReplicateScalar loop:<<Loop>> outer_loop:none
+ private static void testVecReplicateScalar() {
+ for (int j = 0; j <= 8; j++) {
+ int[] a = new int[ARRAY_SIZE];
+ for (int i = 0; i < a.length; i++) {
+ a[i] += 1;
+ }
+ for (int i = 0; i < a.length; i++) {
+ expectEquals(1, a[i]);
+ }
+ }
+ }
+
+ // Check that VecSetScalars, VecReduce, VecExtractScalar are not reordered.
+ /// CHECK-START-ARM64: void Main.testVecSetScalars() scheduler (before)
+ /// CHECK: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK: NewArray loop:<<Loop>> outer_loop:none
+ /// CHECK: VecSetScalars loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK: VecReduce loop:<<Loop>> outer_loop:none
+ /// CHECK: VecExtractScalar loop:<<Loop>> outer_loop:none
+ /// CHECK: InvokeStaticOrDirect loop:<<Loop>> outer_loop:none
+ /// CHECK: InvokeStaticOrDirect loop:<<Loop>> outer_loop:none
+
+ /// CHECK-START-ARM64: void Main.testVecSetScalars() scheduler (after)
+ /// CHECK: Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK: NewArray loop:<<Loop>> outer_loop:none
+ /// CHECK: VecSetScalars loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK: VecReduce loop:<<Loop>> outer_loop:none
+ /// CHECK: VecExtractScalar loop:<<Loop>> outer_loop:none
+ /// CHECK: InvokeStaticOrDirect loop:<<Loop>> outer_loop:none
+ /// CHECK: InvokeStaticOrDirect loop:<<Loop>> outer_loop:none
+ private static void testVecSetScalars() {
+ for (int j = 0; j <= 8; j++) {
+ int[] a = new int[ARRAY_SIZE];
+ int s = 5;
+ for (int i = 0; i < ARRAY_SIZE; i++) {
+ s+=a[i];
+ }
+ expectEquals(a[0], 0);
+ expectEquals(s, 5);
+ }
+ }
+
public static void main(String[] args) {
+ testVecSetScalars();
+ testVecReplicateScalar();
if ((arrayAccess() + intDiv(10)) != -35) {
System.out.println("FAIL");
}
diff --git a/test/AllFields/AllFields.java b/test/AllFields/AllFields.java
index d5eac8fa2e..24f8ba1a0b 100644
--- a/test/AllFields/AllFields.java
+++ b/test/AllFields/AllFields.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-class AllFields {
+public class AllFields {
static boolean sZ;
static byte sB;
static char sC;
diff --git a/test/AllFields/AllFieldsSub.java b/test/AllFields/AllFieldsSub.java
new file mode 100644
index 0000000000..d5f933f88d
--- /dev/null
+++ b/test/AllFields/AllFieldsSub.java
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+public class AllFieldsSub extends AllFields { }
diff --git a/test/AllFields/AllFieldsUnrelated.java b/test/AllFields/AllFieldsUnrelated.java
new file mode 100644
index 0000000000..4db66b1886
--- /dev/null
+++ b/test/AllFields/AllFieldsUnrelated.java
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+public class AllFieldsUnrelated { }
diff --git a/tools/libjdwp_oj_art_failures.txt b/tools/external_oj_libjdwp_art_failures.txt
index 145022e7eb..1178af4852 100644
--- a/tools/libjdwp_oj_art_failures.txt
+++ b/tools/external_oj_libjdwp_art_failures.txt
@@ -1,6 +1,9 @@
/*
* This file contains expectations for ART's buildbot. The purpose of this file is
* to temporarily list failing tests and not break the bots.
+ *
+ * This file contains the expectations for the 'libjdwp-aot' and 'libjdwp-jit'
+ * test groups on the chromium buildbot.
*/
[
{
@@ -69,12 +72,6 @@
name: "org.apache.harmony.jpda.tests.jdwp.ObjectReference.IsCollectedTest#testIsCollected001"
},
{
- description: "Test for ddms extensions that are not yet implemented",
- result: EXEC_FAILED,
- bug: 69169846,
- name: "org.apache.harmony.jpda.tests.jdwp.DDM.DDMTest#testChunk001"
-},
-{
description: "Test crashes",
result: EXEC_FAILED,
bug: 69591477,
@@ -84,6 +81,7 @@
description: "Test times out on fugu-debug",
result: EXEC_FAILED,
bug: 70459916,
- name: "org.apache.harmony.jpda.tests.jdwp.VMDebug.VMDebugTest#testVMDebug"
+ names: [ "org.apache.harmony.jpda.tests.jdwp.VMDebug.VMDebugTest#testVMDebug",
+ "org.apache.harmony.jpda.tests.jdwp.VMDebug.VMDebugTest002#testVMDebug" ]
}
]
diff --git a/tools/jfuzz/README.md b/tools/jfuzz/README.md
index 4edfe1b35b..bee2396fea 100644
--- a/tools/jfuzz/README.md
+++ b/tools/jfuzz/README.md
@@ -50,7 +50,7 @@ How to start JFuzz testing
[--report_script=SCRIPT]
[--jfuzz_arg=ARG]
[--true_divergence]
- [--use_dx]
+ [--dexer=DEXER]
where
@@ -66,7 +66,7 @@ where
--report_script : path to script called for each divergence
--jfuzz_arg : argument for jfuzz
--true_divergence : don't bisect timeout divergences
- --use_dx : use dx (rather than jack)
+ --dexer=DEXER : use either dx, d8, or jack to obtain dex files
How to start JFuzz nightly testing
==================================
@@ -87,14 +87,14 @@ How to start J/DexFuzz testing (multi-layered)
[--num_tests=NUM_TESTS]
[--num_inputs=NUM_INPUTS]
[--device=DEVICE]
- [--use_dx]
+ [--dexer=DEXER]
where
- --num_tests : number of tests to run (10000 by default)
- --num_inputs: number of JFuzz programs to generate
- --device : target device serial number (passed to adb -s)
- --use_dx : use dx (rather than jack)
+ --num_tests : number of tests to run (10000 by default)
+ --num_inputs : number of JFuzz programs to generate
+ --device : target device serial number (passed to adb -s)
+ --dexer=DEXER : use either dx, d8, or jack to obtain dex files
Background
==========
diff --git a/tools/jfuzz/run_dex_fuzz_test.py b/tools/jfuzz/run_dex_fuzz_test.py
index ca0aec01cc..fdff9c03fa 100755
--- a/tools/jfuzz/run_dex_fuzz_test.py
+++ b/tools/jfuzz/run_dex_fuzz_test.py
@@ -41,14 +41,14 @@ from common.common import RunCommand
class DexFuzzTester(object):
"""Tester that feeds JFuzz programs into DexFuzz testing."""
- def __init__(self, num_tests, num_inputs, device, use_dx):
+ def __init__(self, num_tests, num_inputs, device, dexer):
"""Constructor for the tester.
Args:
num_tests: int, number of tests to run
num_inputs: int, number of JFuzz programs to generate
device: string, target device serial number (or None)
- use_dx: boolean, if True use dx rather than jack
+ dexer: string, defines dexer
"""
self._num_tests = num_tests
self._num_inputs = num_inputs
@@ -58,7 +58,7 @@ class DexFuzzTester(object):
self._dexfuzz_dir = None
self._inputs_dir = None
self._dexfuzz_env = None
- self._use_dx = use_dx
+ self._dexer = dexer
def __enter__(self):
"""On entry, enters new temp directory after saving current directory.
@@ -109,13 +109,14 @@ class DexFuzzTester(object):
Raises:
FatalError: error when compilation fails
"""
- if self._use_dx:
+ if self._dexer == 'dx' or self._dexer == 'd8':
if RunCommand(['javac', 'Test.java'],
out=None, err='jerr.txt', timeout=30) != RetCode.SUCCESS:
print('Unexpected error while running javac')
raise FatalError('Unexpected error while running javac')
cfiles = glob('*.class')
- if RunCommand(['dx', '--dex', '--output=classes.dex'] + cfiles,
+ dx = 'dx' if self._dexer == 'dx' else 'd8-compat-dx'
+ if RunCommand([dx, '--dex', '--output=classes.dex'] + cfiles,
out=None, err='dxerr.txt', timeout=30) != RetCode.SUCCESS:
print('Unexpected error while running dx')
raise FatalError('Unexpected error while running dx')
@@ -124,7 +125,8 @@ class DexFuzzTester(object):
os.unlink(cfile)
os.unlink('jerr.txt')
os.unlink('dxerr.txt')
- else:
+
+ elif self._dexer == 'jack':
jack_args = ['-cp', GetJackClassPath(), '--output-dex', '.', 'Test.java']
if RunCommand(['jack'] + jack_args, out=None, err='jackerr.txt',
timeout=30) != RetCode.SUCCESS:
@@ -132,6 +134,8 @@ class DexFuzzTester(object):
raise FatalError('Unexpected error while running Jack')
# Cleanup on success (nothing to see).
os.unlink('jackerr.txt')
+ else:
+ raise FatalError('Unknown dexer: ' + self._dexer)
def GenerateJFuzzPrograms(self):
"""Generates JFuzz programs.
@@ -175,16 +179,16 @@ class DexFuzzTester(object):
def main():
# Handle arguments.
parser = argparse.ArgumentParser()
- parser.add_argument('--num_tests', default=1000,
- type=int, help='number of tests to run')
- parser.add_argument('--num_inputs', default=10,
- type=int, help='number of JFuzz program to generate')
- parser.add_argument('--use_dx', default=False, action='store_true',
- help='use dx (rather than jack)')
+ parser.add_argument('--num_tests', default=1000, type=int,
+ help='number of tests to run (default: 1000)')
+ parser.add_argument('--num_inputs', default=10, type=int,
+ help='number of JFuzz program to generate (default: 10)')
+ parser.add_argument('--dexer', default='dx', type=str,
+ help='defines dexer as dx, d8, or jack (default: dx)')
parser.add_argument('--device', help='target device serial number')
args = parser.parse_args()
# Run the DexFuzz tester.
- with DexFuzzTester(args.num_tests, args.num_inputs, args.device, args.use_dx) as fuzzer:
+ with DexFuzzTester(args.num_tests, args.num_inputs, args.device, args.dexer) as fuzzer:
fuzzer.Run()
if __name__ == '__main__':
diff --git a/tools/jfuzz/run_jfuzz_test.py b/tools/jfuzz/run_jfuzz_test.py
index dac1c79817..b88994013e 100755
--- a/tools/jfuzz/run_jfuzz_test.py
+++ b/tools/jfuzz/run_jfuzz_test.py
@@ -43,11 +43,11 @@ from common.common import DeviceTestEnv
BISECTABLE_RET_CODES = (RetCode.SUCCESS, RetCode.ERROR, RetCode.TIMEOUT)
-def GetExecutionModeRunner(use_dx, device, mode):
+def GetExecutionModeRunner(dexer, device, mode):
"""Returns a runner for the given execution mode.
Args:
- use_dx: boolean, if True use dx rather than jack
+ dexer: string, defines dexer
device: string, target device serial number (or None)
mode: string, execution mode
Returns:
@@ -58,13 +58,13 @@ def GetExecutionModeRunner(use_dx, device, mode):
if mode == 'ri':
return TestRunnerRIOnHost()
if mode == 'hint':
- return TestRunnerArtIntOnHost(use_dx)
+ return TestRunnerArtIntOnHost(dexer)
if mode == 'hopt':
- return TestRunnerArtOptOnHost(use_dx)
+ return TestRunnerArtOptOnHost(dexer)
if mode == 'tint':
- return TestRunnerArtIntOnTarget(use_dx, device)
+ return TestRunnerArtIntOnTarget(dexer, device)
if mode == 'topt':
- return TestRunnerArtOptOnTarget(use_dx, device)
+ return TestRunnerArtOptOnTarget(dexer, device)
raise FatalError('Unknown execution mode')
@@ -117,27 +117,30 @@ class TestRunner(object):
class TestRunnerWithHostCompilation(TestRunner):
"""Abstract test runner that supports compilation on host."""
- def __init__(self, use_dx):
+ def __init__(self, dexer):
"""Constructor for the runner with host compilation.
Args:
- use_dx: boolean, if True use dx rather than jack
+ dexer: string, defines dexer
"""
self._jack_args = ['-cp', GetJackClassPath(), '--output-dex', '.',
'Test.java']
- self._use_dx = use_dx
+ self._dexer = dexer
def CompileOnHost(self):
- if self._use_dx:
+ if self._dexer == 'dx' or self._dexer == 'd8':
if RunCommand(['javac', 'Test.java'],
out=None, err=None, timeout=30) == RetCode.SUCCESS:
- retc = RunCommand(['dx', '--dex', '--output=classes.dex'] + glob('*.class'),
+ dx = 'dx' if self._dexer == 'dx' else 'd8-compat-dx'
+ retc = RunCommand([dx, '--dex', '--output=classes.dex'] + glob('*.class'),
out=None, err='dxerr.txt', timeout=30)
else:
retc = RetCode.NOTCOMPILED
- else:
+ elif self._dexer == 'jack':
retc = RunCommand(['jack'] + self._jack_args,
out=None, err='jackerr.txt', timeout=30)
+ else:
+ raise FatalError('Unknown dexer: ' + self._dexer)
return retc
@@ -167,14 +170,14 @@ class TestRunnerRIOnHost(TestRunner):
class TestRunnerArtOnHost(TestRunnerWithHostCompilation):
"""Abstract test runner of Art on host."""
- def __init__(self, use_dx, extra_args=None):
+ def __init__(self, dexer, extra_args=None):
"""Constructor for the Art on host tester.
Args:
- use_dx: boolean, if True use dx rather than jack
+ dexer: string, defines dexer
extra_args: list of strings, extra arguments for dalvikvm
"""
- super().__init__(use_dx)
+ super().__init__(dexer)
self._art_cmd = ['/bin/bash', 'art', '-cp', 'classes.dex']
if extra_args is not None:
self._art_cmd += extra_args
@@ -191,13 +194,13 @@ class TestRunnerArtOnHost(TestRunnerWithHostCompilation):
class TestRunnerArtIntOnHost(TestRunnerArtOnHost):
"""Concrete test runner of interpreter mode Art on host."""
- def __init__(self, use_dx):
+ def __init__(self, dexer):
"""Constructor for the Art on host tester (interpreter).
Args:
- use_dx: boolean, if True use dx rather than jack
+ dexer: string, defines dexer
"""
- super().__init__(use_dx, ['-Xint'])
+ super().__init__(dexer, ['-Xint'])
@property
def description(self):
@@ -214,13 +217,13 @@ class TestRunnerArtIntOnHost(TestRunnerArtOnHost):
class TestRunnerArtOptOnHost(TestRunnerArtOnHost):
"""Concrete test runner of optimizing compiler mode Art on host."""
- def __init__(self, use_dx):
+ def __init__(self, dexer):
"""Constructor for the Art on host tester (optimizing).
Args:
- use_dx: boolean, if True use dx rather than jack
+ dexer: string, defines dexer
"""
- super().__init__(use_dx, None)
+ super().__init__(dexer, None)
@property
def description(self):
@@ -239,15 +242,15 @@ class TestRunnerArtOptOnHost(TestRunnerArtOnHost):
class TestRunnerArtOnTarget(TestRunnerWithHostCompilation):
"""Abstract test runner of Art on target."""
- def __init__(self, use_dx, device, extra_args=None):
+ def __init__(self, dexer, device, extra_args=None):
"""Constructor for the Art on target tester.
Args:
- use_dx: boolean, if True use dx rather than jack
+ dexer: string, defines dexer
device: string, target device serial number (or None)
extra_args: list of strings, extra arguments for dalvikvm
"""
- super().__init__(use_dx)
+ super().__init__(dexer)
self._test_env = DeviceTestEnv('jfuzz_', specific_device=device)
self._dalvik_cmd = ['dalvikvm']
if extra_args is not None:
@@ -281,14 +284,14 @@ class TestRunnerArtOnTarget(TestRunnerWithHostCompilation):
class TestRunnerArtIntOnTarget(TestRunnerArtOnTarget):
"""Concrete test runner of interpreter mode Art on target."""
- def __init__(self, use_dx, device):
+ def __init__(self, dexer, device):
"""Constructor for the Art on target tester (interpreter).
Args:
- use_dx: boolean, if True use dx rather than jack
+ dexer: string, defines dexer
device: string, target device serial number (or None)
"""
- super().__init__(use_dx, device, ['-Xint'])
+ super().__init__(dexer, device, ['-Xint'])
@property
def description(self):
@@ -305,14 +308,14 @@ class TestRunnerArtIntOnTarget(TestRunnerArtOnTarget):
class TestRunnerArtOptOnTarget(TestRunnerArtOnTarget):
"""Concrete test runner of optimizing compiler mode Art on target."""
- def __init__(self, use_dx, device):
+ def __init__(self, dexer, device):
"""Constructor for the Art on target tester (optimizing).
Args:
- use_dx: boolean, if True use dx rather than jack
+ dexer: string, defines dexer
device: string, target device serial number (or None)
"""
- super().__init__(use_dx, device, None)
+ super().__init__(dexer, device, None)
@property
def description(self):
@@ -342,7 +345,7 @@ class JFuzzTester(object):
"""Tester that runs JFuzz many times and report divergences."""
def __init__(self, num_tests, device, mode1, mode2, jfuzz_args,
- report_script, true_divergence_only, use_dx):
+ report_script, true_divergence_only, dexer):
"""Constructor for the tester.
Args:
@@ -353,16 +356,16 @@ class JFuzzTester(object):
jfuzz_args: list of strings, additional arguments for jfuzz
report_script: string, path to script called for each divergence
true_divergence_only: boolean, if True don't bisect timeout divergences
- use_dx: boolean, if True use dx rather than jack
+ dexer: string, defines dexer
"""
self._num_tests = num_tests
self._device = device
- self._runner1 = GetExecutionModeRunner(use_dx, device, mode1)
- self._runner2 = GetExecutionModeRunner(use_dx, device, mode2)
+ self._runner1 = GetExecutionModeRunner(dexer, device, mode1)
+ self._runner2 = GetExecutionModeRunner(dexer, device, mode2)
self._jfuzz_args = jfuzz_args
self._report_script = report_script
self._true_divergence_only = true_divergence_only
- self._use_dx = use_dx
+ self._dexer = dexer
self._save_dir = None
self._results_dir = None
self._jfuzz_dir = None
@@ -405,7 +408,7 @@ class JFuzzTester(object):
print('Directory :', self._results_dir)
print('Exec-mode1:', self._runner1.description)
print('Exec-mode2:', self._runner2.description)
- print('Compiler :', 'dx' if self._use_dx else 'jack')
+ print('Dexer :', self._dexer)
print()
self.ShowStats()
for self._test in range(1, self._num_tests + 1):
@@ -525,8 +528,7 @@ class JFuzzTester(object):
for arg in jfuzz_cmd_str.strip().split(' -')][1:]
wrapped_args = ['--jfuzz_arg={0}'.format(opt) for opt in jfuzz_args]
repro_cmd_str = (os.path.basename(__file__) +
- ' --num_tests=1 ' +
- ('--use_dx ' if self._use_dx else '') +
+ ' --num_tests=1 --dexer=' + self._dexer +
' '.join(wrapped_args))
comment = 'jfuzz {0}\nReproduce test:\n{1}\nReproduce divergence:\n{2}\n'.format(
jfuzz_ver, jfuzz_cmd_str, repro_cmd_str)
@@ -592,21 +594,22 @@ class JFuzzTester(object):
def main():
# Handle arguments.
parser = argparse.ArgumentParser()
- parser.add_argument('--num_tests', default=10000,
- type=int, help='number of tests to run')
+ parser.add_argument('--num_tests', default=10000, type=int,
+ help='number of tests to run')
parser.add_argument('--device', help='target device serial number')
parser.add_argument('--mode1', default='ri',
help='execution mode 1 (default: ri)')
parser.add_argument('--mode2', default='hopt',
help='execution mode 2 (default: hopt)')
- parser.add_argument('--report_script', help='script called for each'
- ' divergence')
+ parser.add_argument('--report_script',
+ help='script called for each divergence')
parser.add_argument('--jfuzz_arg', default=[], dest='jfuzz_args',
- action='append', help='argument for jfuzz')
+ action='append',
+ help='argument for jfuzz')
parser.add_argument('--true_divergence', default=False, action='store_true',
- help='don\'t bisect timeout divergences')
- parser.add_argument('--use_dx', default=False, action='store_true',
- help='use dx (rather than jack)')
+ help='do not bisect timeout divergences')
+ parser.add_argument('--dexer', default='dx', type=str,
+ help='defines dexer as dx, d8, or jack (default: dx)')
args = parser.parse_args()
if args.mode1 == args.mode2:
raise FatalError('Identical execution modes given')
@@ -614,7 +617,7 @@ def main():
with JFuzzTester(args.num_tests,
args.device, args.mode1, args.mode2,
args.jfuzz_args, args.report_script,
- args.true_divergence, args.use_dx) as fuzzer:
+ args.true_divergence, args.dexer) as fuzzer:
fuzzer.Run()
if __name__ == '__main__':
diff --git a/tools/libjdwp_art_failures.txt b/tools/prebuilt_libjdwp_art_failures.txt
index bf1c9370b0..7694a4c7e4 100644
--- a/tools/libjdwp_art_failures.txt
+++ b/tools/prebuilt_libjdwp_art_failures.txt
@@ -1,6 +1,9 @@
/*
* This file contains expectations for ART's buildbot. The purpose of this file is
* to temporarily list failing tests and not break the bots.
+ *
+ * This file contains the expectations for the 'prebuilt-libjdwp-aot' and
+ * 'prebuilt-libjdwp-jit' test groups on the chromium buildbot.
*/
[
{
@@ -67,7 +70,8 @@
{
description: "Tests for VMDebug functionality not implemented in the upstream libjdwp",
result: EXEC_FAILED,
- name: "org.apache.harmony.jpda.tests.jdwp.VMDebug.VMDebugTest#testVMDebug"
+ names: [ "org.apache.harmony.jpda.tests.jdwp.VMDebug.VMDebugTest#testVMDebug",
+ "org.apache.harmony.jpda.tests.jdwp.VMDebug.VMDebugTest002#testVMDebug" ]
},
/* TODO Categorize these failures more. */
{
diff --git a/tools/run-libjdwp-tests.sh b/tools/run-libjdwp-tests.sh
index 47e7c4595d..e116facd98 100755
--- a/tools/run-libjdwp-tests.sh
+++ b/tools/run-libjdwp-tests.sh
@@ -79,7 +79,7 @@ else
args+=(-Xplugin:libopenjdkjvmti.so)
fi
-expect_path=$PWD/art/tools/libjdwp_oj_art_failures.txt
+expect_path=$PWD/art/tools/external_oj_libjdwp_art_failures.txt
function verbose_run() {
echo "$@"
env "$@"
diff --git a/tools/run-prebuilt-libjdwp-tests.sh b/tools/run-prebuilt-libjdwp-tests.sh
index 46c2a153a7..e7f028ae63 100755
--- a/tools/run-prebuilt-libjdwp-tests.sh
+++ b/tools/run-prebuilt-libjdwp-tests.sh
@@ -96,7 +96,7 @@ if [[ ! -f $plugin ]]; then
fi
props_path=$PWD/art/tools/libjdwp-compat.props
-expect_path=$PWD/art/tools/libjdwp_art_failures.txt
+expect_path=$PWD/art/tools/prebuilt_libjdwp_art_failures.txt
function verbose_run() {
echo "$@"