Merge "Skip loop optimization if there is no loop in the graph."
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index d376f29..c319b1a 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -119,8 +119,8 @@
ART_GTEST_dex_to_dex_decompiler_test_DEX_DEPS := VerifierDeps DexToDexDecompiler
# The elf writer test has dependencies on core.oat.
-ART_GTEST_elf_writer_test_HOST_DEPS := $(HOST_CORE_IMAGE_optimizing_no-pic_64) $(HOST_CORE_IMAGE_optimizing_no-pic_32)
-ART_GTEST_elf_writer_test_TARGET_DEPS := $(TARGET_CORE_IMAGE_optimizing_no-pic_64) $(TARGET_CORE_IMAGE_optimizing_no-pic_32)
+ART_GTEST_elf_writer_test_HOST_DEPS := $(HOST_CORE_IMAGE_DEFAULT_64) $(HOST_CORE_IMAGE_DEFAULT_32)
+ART_GTEST_elf_writer_test_TARGET_DEPS := $(TARGET_CORE_IMAGE_DEFAULT_64) $(TARGET_CORE_IMAGE_DEFAULT_32)
ART_GTEST_dex2oat_environment_tests_HOST_DEPS := \
$(HOST_CORE_IMAGE_optimizing_pic_64) \
@@ -158,63 +158,63 @@
$(ART_GTEST_dex2oat_environment_tests_TARGET_DEPS)
# TODO: document why this is needed.
-ART_GTEST_proxy_test_HOST_DEPS := $(HOST_CORE_IMAGE_optimizing_no-pic_64) $(HOST_CORE_IMAGE_optimizing_no-pic_32)
+ART_GTEST_proxy_test_HOST_DEPS := $(HOST_CORE_IMAGE_DEFAULT_64) $(HOST_CORE_IMAGE_DEFAULT_32)
# The dexdump test requires an image and the dexdump utility.
# TODO: rename into dexdump when migration completes
ART_GTEST_dexdump_test_HOST_DEPS := \
- $(HOST_CORE_IMAGE_optimizing_no-pic_64) \
- $(HOST_CORE_IMAGE_optimizing_no-pic_32) \
+ $(HOST_CORE_IMAGE_DEFAULT_64) \
+ $(HOST_CORE_IMAGE_DEFAULT_32) \
$(HOST_OUT_EXECUTABLES)/dexdump2
ART_GTEST_dexdump_test_TARGET_DEPS := \
- $(TARGET_CORE_IMAGE_optimizing_no-pic_64) \
- $(TARGET_CORE_IMAGE_optimizing_no-pic_32) \
+ $(TARGET_CORE_IMAGE_DEFAULT_64) \
+ $(TARGET_CORE_IMAGE_DEFAULT_32) \
dexdump2
# The dexlayout test requires an image and the dexlayout utility.
# TODO: rename into dexdump when migration completes
ART_GTEST_dexlayout_test_HOST_DEPS := \
- $(HOST_CORE_IMAGE_optimizing_no-pic_64) \
- $(HOST_CORE_IMAGE_optimizing_no-pic_32) \
+ $(HOST_CORE_IMAGE_DEFAULT_64) \
+ $(HOST_CORE_IMAGE_DEFAULT_32) \
$(HOST_OUT_EXECUTABLES)/dexlayout \
$(HOST_OUT_EXECUTABLES)/dexdump2
ART_GTEST_dexlayout_test_TARGET_DEPS := \
- $(TARGET_CORE_IMAGE_optimizing_no-pic_64) \
- $(TARGET_CORE_IMAGE_optimizing_no-pic_32) \
+ $(TARGET_CORE_IMAGE_DEFAULT_64) \
+ $(TARGET_CORE_IMAGE_DEFAULT_32) \
dexlayout \
dexdump2
# The dexlist test requires an image and the dexlist utility.
ART_GTEST_dexlist_test_HOST_DEPS := \
- $(HOST_CORE_IMAGE_optimizing_no-pic_64) \
- $(HOST_CORE_IMAGE_optimizing_no-pic_32) \
+ $(HOST_CORE_IMAGE_DEFAULT_64) \
+ $(HOST_CORE_IMAGE_DEFAULT_32) \
$(HOST_OUT_EXECUTABLES)/dexlist
ART_GTEST_dexlist_test_TARGET_DEPS := \
- $(TARGET_CORE_IMAGE_optimizing_no-pic_64) \
- $(TARGET_CORE_IMAGE_optimizing_no-pic_32) \
+ $(TARGET_CORE_IMAGE_DEFAULT_64) \
+ $(TARGET_CORE_IMAGE_DEFAULT_32) \
dexlist
# The imgdiag test has dependencies on core.oat since it needs to load it during the test.
# For the host, also add the installed tool (in the base size, that should suffice). For the
# target, just the module is fine, the sync will happen late enough.
ART_GTEST_imgdiag_test_HOST_DEPS := \
- $(HOST_CORE_IMAGE_optimizing_no-pic_64) \
- $(HOST_CORE_IMAGE_optimizing_no-pic_32) \
+ $(HOST_CORE_IMAGE_DEFAULT_64) \
+ $(HOST_CORE_IMAGE_DEFAULT_32) \
$(HOST_OUT_EXECUTABLES)/imgdiagd
ART_GTEST_imgdiag_test_TARGET_DEPS := \
- $(TARGET_CORE_IMAGE_optimizing_no-pic_64) \
- $(TARGET_CORE_IMAGE_optimizing_no-pic_32) \
+ $(TARGET_CORE_IMAGE_DEFAULT_64) \
+ $(TARGET_CORE_IMAGE_DEFAULT_32) \
imgdiagd
# Oatdump test requires an image and oatfile to dump.
ART_GTEST_oatdump_test_HOST_DEPS := \
- $(HOST_CORE_IMAGE_optimizing_no-pic_64) \
- $(HOST_CORE_IMAGE_optimizing_no-pic_32) \
+ $(HOST_CORE_IMAGE_DEFAULT_64) \
+ $(HOST_CORE_IMAGE_DEFAULT_32) \
$(HOST_OUT_EXECUTABLES)/oatdumpd \
$(HOST_OUT_EXECUTABLES)/oatdumpds
ART_GTEST_oatdump_test_TARGET_DEPS := \
- $(TARGET_CORE_IMAGE_optimizing_no-pic_64) \
- $(TARGET_CORE_IMAGE_optimizing_no-pic_32) \
+ $(TARGET_CORE_IMAGE_DEFAULT_64) \
+ $(TARGET_CORE_IMAGE_DEFAULT_32) \
oatdump
# Profile assistant tests requires profman utility.
diff --git a/build/Android.oat.mk b/build/Android.oat.mk
index e297b4f..0086660 100644
--- a/build/Android.oat.mk
+++ b/build/Android.oat.mk
@@ -281,3 +281,10 @@
valgrind-test-art-host-dex2oat-target: $(valgrindTARGET_CORE_IMG_OUTS)
valgrind-test-art-host-dex2oat: valgrind-test-art-host-dex2oat-host valgrind-test-art-host-dex2oat-target
+
+# Define a default core image that can be used for things like gtests that
+# need some image to run, but don't otherwise care which image is used.
+HOST_CORE_IMAGE_DEFAULT_32 := $(HOST_CORE_IMAGE_optimizing_pic_32)
+HOST_CORE_IMAGE_DEFAULT_64 := $(HOST_CORE_IMAGE_optimizing_pic_64)
+TARGET_CORE_IMAGE_DEFAULT_32 := $(TARGET_CORE_IMAGE_optimizing_pic_32)
+TARGET_CORE_IMAGE_DEFAULT_64 := $(TARGET_CORE_IMAGE_optimizing_pic_64)
diff --git a/cmdline/cmdline.h b/cmdline/cmdline.h
index f4540ff..98010d7 100644
--- a/cmdline/cmdline.h
+++ b/cmdline/cmdline.h
@@ -267,7 +267,7 @@
std::string file_name;
if (!LocationToFilename(boot_image_location, instruction_set_, &file_name)) {
*error_msg = android::base::StringPrintf("No corresponding file for location '%s' exists",
- file_name.c_str());
+ boot_image_location.c_str());
return false;
}
diff --git a/compiler/elf_writer_test.cc b/compiler/elf_writer_test.cc
index 9669c4a..fa2d78d 100644
--- a/compiler/elf_writer_test.cc
+++ b/compiler/elf_writer_test.cc
@@ -41,7 +41,6 @@
symbol_name, \
build_map)); \
EXPECT_NE(nullptr, addr); \
- EXPECT_LT(static_cast<uintptr_t>(ART_BASE_ADDRESS), reinterpret_cast<uintptr_t>(addr)); \
if ((expected_value) == nullptr) { \
(expected_value) = addr; \
} \
@@ -60,7 +59,7 @@
void* dl_oatlastword = nullptr;
std::unique_ptr<File> file(OS::OpenFileForReading(elf_filename.c_str()));
- ASSERT_TRUE(file.get() != nullptr);
+ ASSERT_TRUE(file.get() != nullptr) << elf_filename;
{
std::string error_msg;
std::unique_ptr<ElfFile> ef(ElfFile::Open(file.get(),
@@ -86,17 +85,22 @@
EXPECT_ELF_FILE_ADDRESS(ef, dl_oatlastword, "oatlastword", true);
}
{
+ uint8_t* base = reinterpret_cast<uint8_t*>(ART_BASE_ADDRESS);
std::string error_msg;
std::unique_ptr<ElfFile> ef(ElfFile::Open(file.get(),
false,
true,
/*low_4gb*/false,
- &error_msg));
+ &error_msg,
+ base));
CHECK(ef.get() != nullptr) << error_msg;
CHECK(ef->Load(file.get(), false, /*low_4gb*/false, &error_msg)) << error_msg;
- EXPECT_EQ(dl_oatdata, ef->FindDynamicSymbolAddress("oatdata"));
- EXPECT_EQ(dl_oatexec, ef->FindDynamicSymbolAddress("oatexec"));
- EXPECT_EQ(dl_oatlastword, ef->FindDynamicSymbolAddress("oatlastword"));
+ EXPECT_EQ(reinterpret_cast<uintptr_t>(dl_oatdata) + reinterpret_cast<uintptr_t>(base),
+ reinterpret_cast<uintptr_t>(ef->FindDynamicSymbolAddress("oatdata")));
+ EXPECT_EQ(reinterpret_cast<uintptr_t>(dl_oatexec) + reinterpret_cast<uintptr_t>(base),
+ reinterpret_cast<uintptr_t>(ef->FindDynamicSymbolAddress("oatexec")));
+ EXPECT_EQ(reinterpret_cast<uintptr_t>(dl_oatlastword) + reinterpret_cast<uintptr_t>(base),
+ reinterpret_cast<uintptr_t>(ef->FindDynamicSymbolAddress("oatlastword")));
}
}
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index bac16cd..8dd423f 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -58,6 +58,9 @@
namespace art {
+// If true, we record the static and direct invokes in the invoke infos.
+static constexpr bool kEnableDexLayoutOptimizations = false;
+
// Return whether a location is consistent with a type.
static bool CheckType(Primitive::Type type, Location location) {
if (location.IsFpuRegister()
@@ -801,7 +804,18 @@
outer_environment_size,
inlining_depth);
- EmitEnvironment(instruction->GetEnvironment(), slow_path);
+ HEnvironment* const environment = instruction->GetEnvironment();
+ EmitEnvironment(environment, slow_path);
+ // Record invoke info, the common case for the trampoline is super and static invokes. Only
+ // record these to reduce oat file size.
+ if (kEnableDexLayoutOptimizations) {
+ if (environment != nullptr &&
+ instruction->IsInvoke() &&
+ instruction->IsInvokeStaticOrDirect()) {
+ HInvoke* const invoke = instruction->AsInvoke();
+ stack_map_stream_.AddInvoke(invoke->GetInvokeType(), invoke->GetDexMethodIndex());
+ }
+ }
stack_map_stream_.EndStackMapEntry();
HLoopInformation* info = instruction->GetBlock()->GetLoopInformation();
@@ -818,7 +832,6 @@
EmitEnvironment(instruction->GetEnvironment(), slow_path);
stack_map_stream_.EndStackMapEntry();
if (kIsDebugBuild) {
- HEnvironment* environment = instruction->GetEnvironment();
for (size_t i = 0, environment_size = environment->Size(); i < environment_size; ++i) {
HInstruction* in_environment = environment->GetInstructionAt(i);
if (in_environment != nullptr) {
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 09612c8d..b779aed 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -5262,7 +5262,7 @@
// Branch cases into compressed and uncompressed for each index's type.
uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
NearLabel done, not_compressed;
- __ testl(Address(obj, count_offset), Immediate(1));
+ __ testb(Address(obj, count_offset), Immediate(1));
codegen_->MaybeRecordImplicitNullCheck(instruction);
static_assert(static_cast<uint32_t>(mirror::StringCompressionFlag::kCompressed) == 0u,
"Expecting 0=compressed, 1=uncompressed");
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index 0879992..179bf6d 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -4720,7 +4720,7 @@
// Branch cases into compressed and uncompressed for each index's type.
uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
NearLabel done, not_compressed;
- __ testl(Address(obj, count_offset), Immediate(1));
+ __ testb(Address(obj, count_offset), Immediate(1));
codegen_->MaybeRecordImplicitNullCheck(instruction);
static_assert(static_cast<uint32_t>(mirror::StringCompressionFlag::kCompressed) == 0u,
"Expecting 0=compressed, 1=uncompressed");
diff --git a/compiler/optimizing/stack_map_stream.cc b/compiler/optimizing/stack_map_stream.cc
index 1bcc8e1..eeae96e 100644
--- a/compiler/optimizing/stack_map_stream.cc
+++ b/compiler/optimizing/stack_map_stream.cc
@@ -41,12 +41,12 @@
current_entry_.inlining_depth = inlining_depth;
current_entry_.inline_infos_start_index = inline_infos_.size();
current_entry_.stack_mask_index = 0;
+ current_entry_.dex_method_index = DexFile::kDexNoIndex;
current_entry_.dex_register_entry.num_dex_registers = num_dex_registers;
current_entry_.dex_register_entry.locations_start_index = dex_register_locations_.size();
current_entry_.dex_register_entry.live_dex_registers_mask = (num_dex_registers != 0)
? ArenaBitVector::Create(allocator_, num_dex_registers, true, kArenaAllocStackMapStream)
: nullptr;
-
if (sp_mask != nullptr) {
stack_mask_max_ = std::max(stack_mask_max_, sp_mask->GetHighestBitSet());
}
@@ -99,6 +99,11 @@
current_dex_register_++;
}
+void StackMapStream::AddInvoke(InvokeType invoke_type, uint32_t dex_method_index) {
+ current_entry_.invoke_type = invoke_type;
+ current_entry_.dex_method_index = dex_method_index;
+}
+
void StackMapStream::BeginInlineInfoEntry(ArtMethod* method,
uint32_t dex_pc,
uint32_t num_dex_registers,
@@ -166,6 +171,7 @@
encoding.inline_info.num_entries,
encoding.register_mask.num_entries,
encoding.stack_mask.num_entries);
+ ComputeInvokeInfoEncoding(&encoding);
DCHECK_EQ(code_info_encoding_.size(), 0u);
encoding.Compress(&code_info_encoding_);
encoding.ComputeTableOffsets();
@@ -212,6 +218,24 @@
return size;
}
+void StackMapStream::ComputeInvokeInfoEncoding(CodeInfoEncoding* encoding) {
+ DCHECK(encoding != nullptr);
+ uint32_t native_pc_max = 0;
+ uint16_t method_index_max = 0;
+ size_t invoke_infos_count = 0;
+ size_t invoke_type_max = 0;
+ for (const StackMapEntry& entry : stack_maps_) {
+ if (entry.dex_method_index != DexFile::kDexNoIndex) {
+ native_pc_max = std::max(native_pc_max, entry.native_pc_code_offset.CompressedValue());
+ method_index_max = std::max(method_index_max, static_cast<uint16_t>(entry.dex_method_index));
+ invoke_type_max = std::max(invoke_type_max, static_cast<size_t>(entry.invoke_type));
+ ++invoke_infos_count;
+ }
+ }
+ encoding->invoke_info.num_entries = invoke_infos_count;
+ encoding->invoke_info.encoding.SetFromSizes(native_pc_max, invoke_type_max, method_index_max);
+}
+
void StackMapStream::ComputeInlineInfoEncoding(InlineInfoEncoding* encoding,
size_t dex_register_maps_bytes) {
uint32_t method_index_max = 0;
@@ -304,6 +328,7 @@
ArenaBitVector empty_bitmask(allocator_, 0, /* expandable */ false, kArenaAllocStackMapStream);
uintptr_t next_dex_register_map_offset = 0;
uintptr_t next_inline_info_index = 0;
+ size_t invoke_info_idx = 0;
for (size_t i = 0, e = stack_maps_.size(); i < e; ++i) {
StackMap stack_map = code_info.GetStackMapAt(i, encoding);
StackMapEntry entry = stack_maps_[i];
@@ -318,6 +343,14 @@
dex_register_locations_region);
stack_map.SetDexRegisterMapOffset(encoding.stack_map.encoding, offset);
+ if (entry.dex_method_index != DexFile::kDexNoIndex) {
+ InvokeInfo invoke_info(code_info.GetInvokeInfo(encoding, invoke_info_idx));
+ invoke_info.SetNativePcCodeOffset(encoding.invoke_info.encoding, entry.native_pc_code_offset);
+ invoke_info.SetInvokeType(encoding.invoke_info.encoding, entry.invoke_type);
+ invoke_info.SetMethodIndex(encoding.invoke_info.encoding, entry.dex_method_index);
+ ++invoke_info_idx;
+ }
+
// Set the inlining info.
if (entry.inlining_depth != 0) {
InlineInfo inline_info = code_info.GetInlineInfo(next_inline_info_index, encoding);
@@ -528,6 +561,7 @@
CodeInfo code_info(region);
CodeInfoEncoding encoding = code_info.ExtractEncoding();
DCHECK_EQ(code_info.GetNumberOfStackMaps(encoding), stack_maps_.size());
+ size_t invoke_info_index = 0;
for (size_t s = 0; s < stack_maps_.size(); ++s) {
const StackMap stack_map = code_info.GetStackMapAt(s, encoding);
const StackMapEncoding& stack_map_encoding = encoding.stack_map.encoding;
@@ -552,7 +586,14 @@
DCHECK_EQ(stack_mask.LoadBit(b), 0u);
}
}
-
+ if (entry.dex_method_index != DexFile::kDexNoIndex) {
+ InvokeInfo invoke_info = code_info.GetInvokeInfo(encoding, invoke_info_index);
+ DCHECK_EQ(invoke_info.GetNativePcOffset(encoding.invoke_info.encoding, instruction_set_),
+ entry.native_pc_code_offset.Uint32Value(instruction_set_));
+ DCHECK_EQ(invoke_info.GetInvokeType(encoding.invoke_info.encoding), entry.invoke_type);
+ DCHECK_EQ(invoke_info.GetMethodIndex(encoding.invoke_info.encoding), entry.dex_method_index);
+ invoke_info_index++;
+ }
CheckDexRegisterMap(code_info,
code_info.GetDexRegisterMapOf(
stack_map, encoding, entry.dex_register_entry.num_dex_registers),
diff --git a/compiler/optimizing/stack_map_stream.h b/compiler/optimizing/stack_map_stream.h
index bba3d51..4225a87 100644
--- a/compiler/optimizing/stack_map_stream.h
+++ b/compiler/optimizing/stack_map_stream.h
@@ -118,6 +118,8 @@
uint32_t register_mask_index;
DexRegisterMapEntry dex_register_entry;
size_t dex_register_map_index;
+ InvokeType invoke_type;
+ uint32_t dex_method_index;
};
struct InlineInfoEntry {
@@ -138,6 +140,8 @@
void AddDexRegisterEntry(DexRegisterLocation::Kind kind, int32_t value);
+ void AddInvoke(InvokeType type, uint32_t dex_method_index);
+
void BeginInlineInfoEntry(ArtMethod* method,
uint32_t dex_pc,
uint32_t num_dex_registers,
@@ -184,6 +188,14 @@
bool DexRegisterMapEntryEquals(const DexRegisterMapEntry& a, const DexRegisterMapEntry& b) const;
// Fill in the corresponding entries of a register map.
+ void ComputeInvokeInfoEncoding(CodeInfoEncoding* encoding);
+
+ // Returns the index of an entry with the same dex register map as the current_entry,
+ // or kNoSameDexMapFound if no such entry exists.
+ size_t FindEntryWithTheSameDexMap();
+ bool HaveTheSameDexMaps(const StackMapEntry& a, const StackMapEntry& b) const;
+
+ // Fill in the corresponding entries of a register map.
void FillInDexRegisterMap(DexRegisterMap dex_register_map,
uint32_t num_dex_registers,
const BitVector& live_dex_registers_mask,
diff --git a/compiler/optimizing/stack_map_test.cc b/compiler/optimizing/stack_map_test.cc
index 0416951..330f7f2 100644
--- a/compiler/optimizing/stack_map_test.cc
+++ b/compiler/optimizing/stack_map_test.cc
@@ -934,7 +934,6 @@
EXPECT_EQ(offset_mips64.Uint32Value(kMips64), kMips64InstructionAlignment);
}
-
TEST(StackMapTest, TestDeduplicateStackMask) {
ArenaPool pool;
ArenaAllocator arena(&pool);
@@ -963,4 +962,48 @@
stack_map2.GetStackMaskIndex(encoding.stack_map.encoding));
}
+TEST(StackMapTest, TestInvokeInfo) {
+ ArenaPool pool;
+ ArenaAllocator arena(&pool);
+ StackMapStream stream(&arena, kRuntimeISA);
+
+ ArenaBitVector sp_mask(&arena, 0, true);
+ sp_mask.SetBit(1);
+ stream.BeginStackMapEntry(0, 4, 0x3, &sp_mask, 0, 0);
+ stream.AddInvoke(kSuper, 1);
+ stream.EndStackMapEntry();
+ stream.BeginStackMapEntry(0, 8, 0x3, &sp_mask, 0, 0);
+ stream.AddInvoke(kStatic, 3);
+ stream.EndStackMapEntry();
+ stream.BeginStackMapEntry(0, 16, 0x3, &sp_mask, 0, 0);
+ stream.AddInvoke(kDirect, 65535);
+ stream.EndStackMapEntry();
+
+ const size_t size = stream.PrepareForFillIn();
+ MemoryRegion region(arena.Alloc(size, kArenaAllocMisc), size);
+ stream.FillIn(region);
+
+ CodeInfo code_info(region);
+ CodeInfoEncoding encoding = code_info.ExtractEncoding();
+ ASSERT_EQ(3u, code_info.GetNumberOfStackMaps(encoding));
+
+ InvokeInfo invoke1(code_info.GetInvokeInfoForNativePcOffset(4, encoding));
+ InvokeInfo invoke2(code_info.GetInvokeInfoForNativePcOffset(8, encoding));
+ InvokeInfo invoke3(code_info.GetInvokeInfoForNativePcOffset(16, encoding));
+ InvokeInfo invoke_invalid(code_info.GetInvokeInfoForNativePcOffset(12, encoding));
+ EXPECT_FALSE(invoke_invalid.IsValid()); // No entry for that index.
+ EXPECT_TRUE(invoke1.IsValid());
+ EXPECT_TRUE(invoke2.IsValid());
+ EXPECT_TRUE(invoke3.IsValid());
+ EXPECT_EQ(invoke1.GetInvokeType(encoding.invoke_info.encoding), kSuper);
+ EXPECT_EQ(invoke1.GetMethodIndex(encoding.invoke_info.encoding), 1u);
+ EXPECT_EQ(invoke1.GetNativePcOffset(encoding.invoke_info.encoding, kRuntimeISA), 4u);
+ EXPECT_EQ(invoke2.GetInvokeType(encoding.invoke_info.encoding), kStatic);
+ EXPECT_EQ(invoke2.GetMethodIndex(encoding.invoke_info.encoding), 3u);
+ EXPECT_EQ(invoke2.GetNativePcOffset(encoding.invoke_info.encoding, kRuntimeISA), 8u);
+ EXPECT_EQ(invoke3.GetInvokeType(encoding.invoke_info.encoding), kDirect);
+ EXPECT_EQ(invoke3.GetMethodIndex(encoding.invoke_info.encoding), 65535u);
+ EXPECT_EQ(invoke3.GetNativePcOffset(encoding.invoke_info.encoding, kRuntimeISA), 16u);
+}
+
} // namespace art
diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc
index 5dcdd9e..6881f75 100644
--- a/dex2oat/dex2oat_test.cc
+++ b/dex2oat/dex2oat_test.cc
@@ -400,9 +400,9 @@
TEST_F(Dex2oatSwapUseTest, CheckSwapUsage) {
// The `native_alloc_2_ >= native_alloc_1_` assertion below may not
- // hold true on some x86 systems when read barriers are enabled;
- // disable this test while we investigate (b/29259363).
- TEST_DISABLED_FOR_READ_BARRIER_ON_X86();
+ // hold true on some x86 systems; disable this test while we
+ // investigate (b/29259363).
+ TEST_DISABLED_FOR_X86();
RunTest(false /* use_fd */,
false /* expect_use */);
diff --git a/dexlayout/dex_ir.cc b/dexlayout/dex_ir.cc
index 43de342..2d9bbfd 100644
--- a/dexlayout/dex_ir.cc
+++ b/dexlayout/dex_ir.cc
@@ -466,8 +466,8 @@
AnnotationSetItem* Collections::CreateAnnotationSetItem(const DexFile& dex_file,
- const DexFile::AnnotationSetItem& disk_annotations_item, uint32_t offset) {
- if (disk_annotations_item.size_ == 0 && offset == 0) {
+ const DexFile::AnnotationSetItem* disk_annotations_item, uint32_t offset) {
+ if (disk_annotations_item == nullptr || (disk_annotations_item->size_ == 0 && offset == 0)) {
return nullptr;
}
auto found_anno_set_item = AnnotationSetItems().find(offset);
@@ -475,14 +475,14 @@
return found_anno_set_item->second.get();
}
std::vector<AnnotationItem*>* items = new std::vector<AnnotationItem*>();
- for (uint32_t i = 0; i < disk_annotations_item.size_; ++i) {
+ for (uint32_t i = 0; i < disk_annotations_item->size_; ++i) {
const DexFile::AnnotationItem* annotation =
- dex_file.GetAnnotationItem(&disk_annotations_item, i);
+ dex_file.GetAnnotationItem(disk_annotations_item, i);
if (annotation == nullptr) {
continue;
}
AnnotationItem* annotation_item =
- CreateAnnotationItem(annotation, disk_annotations_item.entries_[i]);
+ CreateAnnotationItem(annotation, disk_annotations_item->entries_[i]);
items->push_back(annotation_item);
}
AnnotationSetItem* annotation_set_item = new AnnotationSetItem(items);
@@ -501,7 +501,7 @@
AnnotationSetItem* class_annotation = nullptr;
if (class_set_item != nullptr) {
uint32_t offset = disk_annotations_item->class_annotations_off_;
- class_annotation = CreateAnnotationSetItem(dex_file, *class_set_item, offset);
+ class_annotation = CreateAnnotationSetItem(dex_file, class_set_item, offset);
}
const DexFile::FieldAnnotationsItem* fields =
dex_file.GetFieldAnnotations(disk_annotations_item);
@@ -514,7 +514,7 @@
dex_file.GetFieldAnnotationSetItem(fields[i]);
uint32_t annotation_set_offset = fields[i].annotations_off_;
AnnotationSetItem* annotation_set_item =
- CreateAnnotationSetItem(dex_file, *field_set_item, annotation_set_offset);
+ CreateAnnotationSetItem(dex_file, field_set_item, annotation_set_offset);
field_annotations->push_back(std::unique_ptr<FieldAnnotation>(
new FieldAnnotation(field_id, annotation_set_item)));
}
@@ -530,7 +530,7 @@
dex_file.GetMethodAnnotationSetItem(methods[i]);
uint32_t annotation_set_offset = methods[i].annotations_off_;
AnnotationSetItem* annotation_set_item =
- CreateAnnotationSetItem(dex_file, *method_set_item, annotation_set_offset);
+ CreateAnnotationSetItem(dex_file, method_set_item, annotation_set_offset);
method_annotations->push_back(std::unique_ptr<MethodAnnotation>(
new MethodAnnotation(method_id, annotation_set_item)));
}
@@ -569,7 +569,7 @@
const DexFile::AnnotationSetItem* annotation_set_item =
dex_file.GetSetRefItemItem(&annotation_set_ref_list->list_[i]);
uint32_t set_offset = annotation_set_ref_list->list_[i].annotations_off_;
- annotations->push_back(CreateAnnotationSetItem(dex_file, *annotation_set_item, set_offset));
+ annotations->push_back(CreateAnnotationSetItem(dex_file, annotation_set_item, set_offset));
}
set_ref_list = new AnnotationSetRefList(annotations);
annotation_set_ref_lists_.AddItem(set_ref_list, offset);
diff --git a/dexlayout/dex_ir.h b/dexlayout/dex_ir.h
index 3a5b644..96afb90 100644
--- a/dexlayout/dex_ir.h
+++ b/dexlayout/dex_ir.h
@@ -194,7 +194,7 @@
EncodedArrayItem* CreateEncodedArrayItem(const uint8_t* static_data, uint32_t offset);
AnnotationItem* CreateAnnotationItem(const DexFile::AnnotationItem* annotation, uint32_t offset);
AnnotationSetItem* CreateAnnotationSetItem(const DexFile& dex_file,
- const DexFile::AnnotationSetItem& disk_annotations_item, uint32_t offset);
+ const DexFile::AnnotationSetItem* disk_annotations_item, uint32_t offset);
AnnotationsDirectoryItem* CreateAnnotationsDirectoryItem(const DexFile& dex_file,
const DexFile::AnnotationsDirectoryItem* disk_annotations_item, uint32_t offset);
CodeItem* CreateCodeItem(
diff --git a/disassembler/disassembler_x86.cc b/disassembler/disassembler_x86.cc
index ff05733..a289433 100644
--- a/disassembler/disassembler_x86.cc
+++ b/disassembler/disassembler_x86.cc
@@ -1306,7 +1306,7 @@
has_modrm = true;
reg_is_opcode = true;
store = true;
- immediate_bytes = ((instr[1] & 0x38) == 0) ? 1 : 0;
+ immediate_bytes = ((instr[1] & 0x38) == 0) ? (instr[0] == 0xF7 ? 4 : 1) : 0;
break;
case 0xFF:
{
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index 9a3b28b..a0919a1 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -587,6 +587,7 @@
kByteKindCodeInfoLocationCatalog,
kByteKindCodeInfoDexRegisterMap,
kByteKindCodeInfoEncoding,
+ kByteKindCodeInfoInvokeInfo,
kByteKindCodeInfoStackMasks,
kByteKindCodeInfoRegisterMasks,
kByteKindStackMapNativePc,
@@ -637,6 +638,7 @@
Dump(os, "CodeInfoDexRegisterMap ", bits[kByteKindCodeInfoDexRegisterMap], sum);
Dump(os, "CodeInfoStackMasks ", bits[kByteKindCodeInfoStackMasks], sum);
Dump(os, "CodeInfoRegisterMasks ", bits[kByteKindCodeInfoRegisterMasks], sum);
+ Dump(os, "CodeInfoInvokeInfo ", bits[kByteKindCodeInfoInvokeInfo], sum);
// Stack map section.
const int64_t stack_map_bits = std::accumulate(bits + kByteKindStackMapFirst,
bits + kByteKindStackMapLast + 1,
@@ -1016,7 +1018,9 @@
dex_orig_name = dex_file_location.substr(dex_orig_pos + 1);
// A more elegant approach to efficiently name user installed apps is welcome
- if (dex_orig_name.size() == 8 && !dex_orig_name.compare("base.apk")) {
+ if (dex_orig_name.size() == 8 &&
+ dex_orig_name.compare("base.apk") == 0 &&
+ dex_orig_pos != std::string::npos) {
dex_file_location.erase(dex_orig_pos, strlen("base.apk") + 1);
size_t apk_orig_pos = dex_file_location.rfind('/');
if (apk_orig_pos != std::string::npos) {
@@ -1592,10 +1596,8 @@
CodeInfoEncoding encoding(helper.GetEncoding());
StackMapEncoding stack_map_encoding(encoding.stack_map.encoding);
const size_t num_stack_maps = encoding.stack_map.num_entries;
- std::vector<uint8_t> size_vector;
- encoding.Compress(&size_vector);
if (stats_.AddBitsIfUnique(Stats::kByteKindCodeInfoEncoding,
- size_vector.size() * kBitsPerByte,
+ encoding.HeaderSize() * kBitsPerByte,
oat_method.GetVmapTable())) {
// Stack maps
stats_.AddBits(
@@ -1627,6 +1629,13 @@
Stats::kByteKindCodeInfoRegisterMasks,
encoding.register_mask.encoding.BitSize() * encoding.register_mask.num_entries);
+ // Invoke infos
+ if (encoding.invoke_info.num_entries > 0u) {
+ stats_.AddBits(
+ Stats::kByteKindCodeInfoInvokeInfo,
+ encoding.invoke_info.encoding.BitSize() * encoding.invoke_info.num_entries);
+ }
+
// Location catalog
const size_t location_catalog_bytes =
helper.GetCodeInfo().GetDexRegisterLocationCatalogSize(encoding);
diff --git a/runtime/Android.bp b/runtime/Android.bp
index d3a81a9..d136aa1 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -143,7 +143,6 @@
"native_bridge_art_interface.cc",
"native_stack_dump.cc",
"native/dalvik_system_DexFile.cc",
- "native/dalvik_system_InMemoryDexClassLoader_DexData.cc",
"native/dalvik_system_VMDebug.cc",
"native/dalvik_system_VMRuntime.cc",
"native/dalvik_system_VMStack.cc",
diff --git a/runtime/base/mutex.cc b/runtime/base/mutex.cc
index 7bba944..b93b293 100644
--- a/runtime/base/mutex.cc
+++ b/runtime/base/mutex.cc
@@ -1167,6 +1167,8 @@
expected_mutexes_on_weak_ref_access_.push_back(dex_lock_);
classlinker_classes_lock_->SetShouldRespondToEmptyCheckpointRequest(true);
expected_mutexes_on_weak_ref_access_.push_back(classlinker_classes_lock_);
+ jni_libraries_lock_->SetShouldRespondToEmptyCheckpointRequest(true);
+ expected_mutexes_on_weak_ref_access_.push_back(jni_libraries_lock_);
InitConditions();
}
diff --git a/runtime/common_runtime_test.cc b/runtime/common_runtime_test.cc
index fc82264..78ba6e7 100644
--- a/runtime/common_runtime_test.cc
+++ b/runtime/common_runtime_test.cc
@@ -625,9 +625,9 @@
if (IsHost()) {
const char* host_dir = getenv("ANDROID_HOST_OUT");
CHECK(host_dir != nullptr);
- location = StringPrintf("%s/framework/core-npic.%s", host_dir, suffix);
+ location = StringPrintf("%s/framework/core.%s", host_dir, suffix);
} else {
- location = StringPrintf("/data/art-test/core-npic.%s", suffix);
+ location = StringPrintf("/data/art-test/core.%s", suffix);
}
return location;
diff --git a/runtime/common_runtime_test.h b/runtime/common_runtime_test.h
index 17e3729..d7abe2a 100644
--- a/runtime/common_runtime_test.h
+++ b/runtime/common_runtime_test.h
@@ -223,9 +223,9 @@
return; \
}
-#define TEST_DISABLED_FOR_READ_BARRIER_ON_X86() \
- if (kUseReadBarrier && kRuntimeISA == kX86) { \
- printf("WARNING: TEST DISABLED FOR READ BARRIER ON X86\n"); \
+#define TEST_DISABLED_FOR_X86() \
+ if (kRuntimeISA == kX86) { \
+ printf("WARNING: TEST DISABLED FOR X86\n"); \
return; \
}
diff --git a/runtime/dex_file_annotations.cc b/runtime/dex_file_annotations.cc
index a95f94c..d39ea35 100644
--- a/runtime/dex_file_annotations.cc
+++ b/runtime/dex_file_annotations.cc
@@ -299,6 +299,7 @@
return result.GetL();
}
+template <bool kTransactionActive>
bool ProcessAnnotationValue(Handle<mirror::Class> klass,
const uint8_t** annotation_ptr,
DexFile::AnnotationValue* annotation_value,
@@ -409,22 +410,21 @@
}
PointerSize pointer_size = class_linker->GetImagePointerSize();
set_object = true;
- DCHECK(!Runtime::Current()->IsActiveTransaction());
if (method->IsConstructor()) {
if (pointer_size == PointerSize::k64) {
element_object = mirror::Constructor::CreateFromArtMethod<PointerSize::k64,
- false>(self, method);
+ kTransactionActive>(self, method);
} else {
element_object = mirror::Constructor::CreateFromArtMethod<PointerSize::k32,
- false>(self, method);
+ kTransactionActive>(self, method);
}
} else {
if (pointer_size == PointerSize::k64) {
element_object = mirror::Method::CreateFromArtMethod<PointerSize::k64,
- false>(self, method);
+ kTransactionActive>(self, method);
} else {
element_object = mirror::Method::CreateFromArtMethod<PointerSize::k32,
- false>(self, method);
+ kTransactionActive>(self, method);
}
}
if (element_object == nullptr) {
@@ -449,9 +449,11 @@
set_object = true;
PointerSize pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
if (pointer_size == PointerSize::k64) {
- element_object = mirror::Field::CreateFromArtField<PointerSize::k64>(self, field, true);
+ element_object = mirror::Field::CreateFromArtField<PointerSize::k64,
+ kTransactionActive>(self, field, true);
} else {
- element_object = mirror::Field::CreateFromArtField<PointerSize::k32>(self, field, true);
+ element_object = mirror::Field::CreateFromArtField<PointerSize::k32,
+ kTransactionActive>(self, field, true);
}
if (element_object == nullptr) {
return false;
@@ -497,45 +499,49 @@
}
DexFile::AnnotationValue new_annotation_value;
for (uint32_t i = 0; i < size; ++i) {
- if (!ProcessAnnotationValue(klass, &annotation, &new_annotation_value,
- component_type, DexFile::kPrimitivesOrObjects)) {
+ if (!ProcessAnnotationValue<kTransactionActive>(klass,
+ &annotation,
+ &new_annotation_value,
+ component_type,
+ DexFile::kPrimitivesOrObjects)) {
return false;
}
if (!component_type->IsPrimitive()) {
mirror::Object* obj = new_annotation_value.value_.GetL();
- new_array->AsObjectArray<mirror::Object>()->SetWithoutChecks<false>(i, obj);
+ new_array->AsObjectArray<mirror::Object>()->
+ SetWithoutChecks<kTransactionActive>(i, obj);
} else {
switch (new_annotation_value.type_) {
case DexFile::kDexAnnotationByte:
- new_array->AsByteArray()->SetWithoutChecks<false>(
+ new_array->AsByteArray()->SetWithoutChecks<kTransactionActive>(
i, new_annotation_value.value_.GetB());
break;
case DexFile::kDexAnnotationShort:
- new_array->AsShortArray()->SetWithoutChecks<false>(
+ new_array->AsShortArray()->SetWithoutChecks<kTransactionActive>(
i, new_annotation_value.value_.GetS());
break;
case DexFile::kDexAnnotationChar:
- new_array->AsCharArray()->SetWithoutChecks<false>(
+ new_array->AsCharArray()->SetWithoutChecks<kTransactionActive>(
i, new_annotation_value.value_.GetC());
break;
case DexFile::kDexAnnotationInt:
- new_array->AsIntArray()->SetWithoutChecks<false>(
+ new_array->AsIntArray()->SetWithoutChecks<kTransactionActive>(
i, new_annotation_value.value_.GetI());
break;
case DexFile::kDexAnnotationLong:
- new_array->AsLongArray()->SetWithoutChecks<false>(
+ new_array->AsLongArray()->SetWithoutChecks<kTransactionActive>(
i, new_annotation_value.value_.GetJ());
break;
case DexFile::kDexAnnotationFloat:
- new_array->AsFloatArray()->SetWithoutChecks<false>(
+ new_array->AsFloatArray()->SetWithoutChecks<kTransactionActive>(
i, new_annotation_value.value_.GetF());
break;
case DexFile::kDexAnnotationDouble:
- new_array->AsDoubleArray()->SetWithoutChecks<false>(
+ new_array->AsDoubleArray()->SetWithoutChecks<kTransactionActive>(
i, new_annotation_value.value_.GetD());
break;
case DexFile::kDexAnnotationBoolean:
- new_array->AsBooleanArray()->SetWithoutChecks<false>(
+ new_array->AsBooleanArray()->SetWithoutChecks<kTransactionActive>(
i, new_annotation_value.value_.GetZ());
break;
default:
@@ -611,8 +617,11 @@
annotation_method->GetReturnType(true /* resolve */)));
DexFile::AnnotationValue annotation_value;
- if (!ProcessAnnotationValue(klass, annotation, &annotation_value, method_return,
- DexFile::kAllObjects)) {
+ if (!ProcessAnnotationValue<false>(klass,
+ annotation,
+ &annotation_value,
+ method_return,
+ DexFile::kAllObjects)) {
return nullptr;
}
Handle<mirror::Object> value_object(hs.NewHandle(annotation_value.value_.GetL()));
@@ -716,8 +725,18 @@
return nullptr;
}
DexFile::AnnotationValue annotation_value;
- if (!ProcessAnnotationValue(klass, &annotation, &annotation_value, array_class,
- DexFile::kAllObjects)) {
+ bool result = Runtime::Current()->IsActiveTransaction()
+ ? ProcessAnnotationValue<true>(klass,
+ &annotation,
+ &annotation_value,
+ array_class,
+ DexFile::kAllObjects)
+ : ProcessAnnotationValue<false>(klass,
+ &annotation,
+ &annotation_value,
+ array_class,
+ DexFile::kAllObjects);
+ if (!result) {
return nullptr;
}
if (annotation_value.type_ != expected_type) {
@@ -949,8 +968,11 @@
StackHandleScope<2> hs(Thread::Current());
Handle<mirror::Class> h_klass(hs.NewHandle(klass));
Handle<mirror::Class> return_type(hs.NewHandle(method->GetReturnType(true /* resolve */)));
- if (!ProcessAnnotationValue(h_klass, &annotation, &annotation_value, return_type,
- DexFile::kAllObjects)) {
+ if (!ProcessAnnotationValue<false>(h_klass,
+ &annotation,
+ &annotation_value,
+ return_type,
+ DexFile::kAllObjects)) {
return nullptr;
}
return annotation_value.value_.GetL();
@@ -1201,8 +1223,11 @@
return nullptr;
}
DexFile::AnnotationValue annotation_value;
- if (!ProcessAnnotationValue(klass, &annotation, &annotation_value,
- ScopedNullHandle<mirror::Class>(), DexFile::kAllRaw)) {
+ if (!ProcessAnnotationValue<false>(klass,
+ &annotation,
+ &annotation_value,
+ ScopedNullHandle<mirror::Class>(),
+ DexFile::kAllRaw)) {
return nullptr;
}
if (annotation_value.type_ != DexFile::kDexAnnotationMethod) {
@@ -1252,9 +1277,11 @@
return false;
}
DexFile::AnnotationValue annotation_value;
- if (!ProcessAnnotationValue(klass, &annotation, &annotation_value,
- ScopedNullHandle<mirror::Class>(),
- DexFile::kAllObjects)) {
+ if (!ProcessAnnotationValue<false>(klass,
+ &annotation,
+ &annotation_value,
+ ScopedNullHandle<mirror::Class>(),
+ DexFile::kAllObjects)) {
return false;
}
if (annotation_value.type_ != DexFile::kDexAnnotationNull &&
@@ -1283,8 +1310,11 @@
return false;
}
DexFile::AnnotationValue annotation_value;
- if (!ProcessAnnotationValue(klass, &annotation, &annotation_value,
- ScopedNullHandle<mirror::Class>(), DexFile::kAllRaw)) {
+ if (!ProcessAnnotationValue<false>(klass,
+ &annotation,
+ &annotation_value,
+ ScopedNullHandle<mirror::Class>(),
+ DexFile::kAllRaw)) {
return false;
}
if (annotation_value.type_ != DexFile::kDexAnnotationInt) {
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index c2bca53..4c3990a 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -358,6 +358,29 @@
}
}
+ static bool GetInvokeType(ArtMethod** sp, InvokeType* invoke_type, uint32_t* dex_method_index)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ DCHECK((*sp)->IsCalleeSaveMethod());
+ const size_t callee_frame_size = GetCalleeSaveFrameSize(kRuntimeISA, Runtime::kSaveRefsAndArgs);
+ ArtMethod** caller_sp = reinterpret_cast<ArtMethod**>(
+ reinterpret_cast<uintptr_t>(sp) + callee_frame_size);
+ uintptr_t outer_pc = QuickArgumentVisitor::GetCallingPc(sp);
+ const OatQuickMethodHeader* current_code = (*caller_sp)->GetOatQuickMethodHeader(outer_pc);
+ if (!current_code->IsOptimized()) {
+ return false;
+ }
+ uintptr_t outer_pc_offset = current_code->NativeQuickPcOffset(outer_pc);
+ CodeInfo code_info = current_code->GetOptimizedCodeInfo();
+ CodeInfoEncoding encoding = code_info.ExtractEncoding();
+ InvokeInfo invoke(code_info.GetInvokeInfoForNativePcOffset(outer_pc_offset, encoding));
+ if (invoke.IsValid()) {
+ *invoke_type = static_cast<InvokeType>(invoke.GetInvokeType(encoding.invoke_info.encoding));
+ *dex_method_index = invoke.GetMethodIndex(encoding.invoke_info.encoding);
+ return true;
+ }
+ return false;
+ }
+
// For the given quick ref and args quick frame, return the caller's PC.
static uintptr_t GetCallingPc(ArtMethod** sp) REQUIRES_SHARED(Locks::mutator_lock_) {
DCHECK((*sp)->IsCalleeSaveMethod());
@@ -977,60 +1000,87 @@
ArtMethod* caller = nullptr;
if (!called_method_known_on_entry) {
caller = QuickArgumentVisitor::GetCallingMethod(sp);
- uint32_t dex_pc = QuickArgumentVisitor::GetCallingDexPc(sp);
- const DexFile::CodeItem* code;
called_method.dex_file = caller->GetDexFile();
- code = caller->GetCodeItem();
- CHECK_LT(dex_pc, code->insns_size_in_code_units_);
- const Instruction* instr = Instruction::At(&code->insns_[dex_pc]);
- Instruction::Code instr_code = instr->Opcode();
- bool is_range;
- switch (instr_code) {
- case Instruction::INVOKE_DIRECT:
- invoke_type = kDirect;
- is_range = false;
- break;
- case Instruction::INVOKE_DIRECT_RANGE:
- invoke_type = kDirect;
- is_range = true;
- break;
- case Instruction::INVOKE_STATIC:
- invoke_type = kStatic;
- is_range = false;
- break;
- case Instruction::INVOKE_STATIC_RANGE:
- invoke_type = kStatic;
- is_range = true;
- break;
- case Instruction::INVOKE_SUPER:
- invoke_type = kSuper;
- is_range = false;
- break;
- case Instruction::INVOKE_SUPER_RANGE:
- invoke_type = kSuper;
- is_range = true;
- break;
- case Instruction::INVOKE_VIRTUAL:
- invoke_type = kVirtual;
- is_range = false;
- break;
- case Instruction::INVOKE_VIRTUAL_RANGE:
- invoke_type = kVirtual;
- is_range = true;
- break;
- case Instruction::INVOKE_INTERFACE:
- invoke_type = kInterface;
- is_range = false;
- break;
- case Instruction::INVOKE_INTERFACE_RANGE:
- invoke_type = kInterface;
- is_range = true;
- break;
- default:
- LOG(FATAL) << "Unexpected call into trampoline: " << instr->DumpString(nullptr);
- UNREACHABLE();
+
+ InvokeType stack_map_invoke_type;
+ uint32_t stack_map_dex_method_idx;
+ const bool found_stack_map = QuickArgumentVisitor::GetInvokeType(sp,
+ &stack_map_invoke_type,
+ &stack_map_dex_method_idx);
+ // For debug builds, we make sure both of the paths are consistent by also looking at the dex
+ // code.
+ if (!found_stack_map || kIsDebugBuild) {
+ uint32_t dex_pc = QuickArgumentVisitor::GetCallingDexPc(sp);
+ const DexFile::CodeItem* code;
+ code = caller->GetCodeItem();
+ CHECK_LT(dex_pc, code->insns_size_in_code_units_);
+ const Instruction* instr = Instruction::At(&code->insns_[dex_pc]);
+ Instruction::Code instr_code = instr->Opcode();
+ bool is_range;
+ switch (instr_code) {
+ case Instruction::INVOKE_DIRECT:
+ invoke_type = kDirect;
+ is_range = false;
+ break;
+ case Instruction::INVOKE_DIRECT_RANGE:
+ invoke_type = kDirect;
+ is_range = true;
+ break;
+ case Instruction::INVOKE_STATIC:
+ invoke_type = kStatic;
+ is_range = false;
+ break;
+ case Instruction::INVOKE_STATIC_RANGE:
+ invoke_type = kStatic;
+ is_range = true;
+ break;
+ case Instruction::INVOKE_SUPER:
+ invoke_type = kSuper;
+ is_range = false;
+ break;
+ case Instruction::INVOKE_SUPER_RANGE:
+ invoke_type = kSuper;
+ is_range = true;
+ break;
+ case Instruction::INVOKE_VIRTUAL:
+ invoke_type = kVirtual;
+ is_range = false;
+ break;
+ case Instruction::INVOKE_VIRTUAL_RANGE:
+ invoke_type = kVirtual;
+ is_range = true;
+ break;
+ case Instruction::INVOKE_INTERFACE:
+ invoke_type = kInterface;
+ is_range = false;
+ break;
+ case Instruction::INVOKE_INTERFACE_RANGE:
+ invoke_type = kInterface;
+ is_range = true;
+ break;
+ default:
+ LOG(FATAL) << "Unexpected call into trampoline: " << instr->DumpString(nullptr);
+ UNREACHABLE();
+ }
+ called_method.dex_method_index = (is_range) ? instr->VRegB_3rc() : instr->VRegB_35c();
+ // Check that the invoke matches what we expected, note that this path only happens for debug
+ // builds.
+ if (found_stack_map) {
+ DCHECK_EQ(stack_map_invoke_type, invoke_type);
+ if (invoke_type != kSuper) {
+ // Super may be sharpened.
+ DCHECK_EQ(stack_map_dex_method_idx, called_method.dex_method_index)
+ << called_method.dex_file->PrettyMethod(stack_map_dex_method_idx) << " "
+ << called_method.dex_file->PrettyMethod(called_method.dex_method_index);
+ }
+ } else {
+ VLOG(oat) << "Accessed dex file for invoke " << invoke_type << " "
+ << called_method.dex_method_index;
+ }
+ } else {
+ invoke_type = stack_map_invoke_type;
+ called_method.dex_method_index = stack_map_dex_method_idx;
}
- called_method.dex_method_index = (is_range) ? instr->VRegB_3rc() : instr->VRegB_35c();
} else {
invoke_type = kStatic;
called_method.dex_file = called->GetDexFile();
diff --git a/runtime/gc/collector_type.h b/runtime/gc/collector_type.h
index 7014357..eef4fba 100644
--- a/runtime/gc/collector_type.h
+++ b/runtime/gc/collector_type.h
@@ -55,6 +55,8 @@
kCollectorTypeClassLinker,
// JIT Code cache fake collector.
kCollectorTypeJitCodeCache,
+ // Hprof fake collector.
+ kCollectorTypeHprof,
// Fake collector for installing/removing a system-weak holder.
kCollectorTypeAddRemoveSystemWeakHolder,
};
diff --git a/runtime/gc/gc_cause.cc b/runtime/gc/gc_cause.cc
index 7ff845d..9e34346 100644
--- a/runtime/gc/gc_cause.cc
+++ b/runtime/gc/gc_cause.cc
@@ -39,6 +39,7 @@
case kGcCauseClassLinker: return "ClassLinker";
case kGcCauseJitCodeCache: return "JitCodeCache";
case kGcCauseAddRemoveSystemWeakHolder: return "SystemWeakHolder";
+ case kGcCauseHprof: return "Hprof";
}
LOG(FATAL) << "Unreachable";
UNREACHABLE();
diff --git a/runtime/gc/gc_cause.h b/runtime/gc/gc_cause.h
index f54f0e4..9b285b1 100644
--- a/runtime/gc/gc_cause.h
+++ b/runtime/gc/gc_cause.h
@@ -53,6 +53,8 @@
kGcCauseJitCodeCache,
// Not a real GC cause, used to add or remove system-weak holders.
kGcCauseAddRemoveSystemWeakHolder,
+ // Not a real GC cause, used to hprof running in the middle of GC.
+ kGcCauseHprof,
};
const char* PrettyCause(GcCause cause);
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 0a45fce..c933d04 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -29,6 +29,7 @@
#include "base/arena_allocator.h"
#include "base/dumpable.h"
#include "base/histogram-inl.h"
+#include "base/memory_tool.h"
#include "base/stl_util.h"
#include "base/systrace.h"
#include "base/time_utils.h"
@@ -188,6 +189,7 @@
disable_thread_flip_count_(0),
thread_flip_running_(false),
collector_type_running_(kCollectorTypeNone),
+ thread_running_gc_(nullptr),
last_gc_type_(collector::kGcTypeNone),
next_gc_type_(collector::kGcTypePartial),
capacity_(capacity),
@@ -286,7 +288,7 @@
if (foreground_collector_type_ == kCollectorTypeCC) {
// Need to use a low address so that we can allocate a contiguous
// 2 * Xmx space when there's no image (dex2oat for target).
-#if defined(__LP64__)
+#if defined(__LP64__) || !defined(ADDRESS_SANITIZER)
CHECK_GE(300 * MB, non_moving_space_capacity);
requested_alloc_space_begin = reinterpret_cast<uint8_t*>(300 * MB) - non_moving_space_capacity;
#else
@@ -367,7 +369,7 @@
&error_str));
CHECK(non_moving_space_mem_map != nullptr) << error_str;
// Try to reserve virtual memory at a lower address if we have a separate non moving space.
-#if defined(__LP64__)
+#if defined(__LP64__) || !defined(ADDRESS_SANITIZER)
request_begin = reinterpret_cast<uint8_t*>(300 * MB);
#else
// For 32-bit, use 0x20000000 because asan reserves 0x04000000 - 0x20000000.
@@ -987,7 +989,9 @@
// Continuous spaces don't necessarily have bitmaps.
accounting::ContinuousSpaceBitmap* live_bitmap = continuous_space->GetLiveBitmap();
accounting::ContinuousSpaceBitmap* mark_bitmap = continuous_space->GetMarkBitmap();
- if (live_bitmap != nullptr) {
+ // The region space bitmap is not added since VisitObjects visits the region space objects with
+ // special handling.
+ if (live_bitmap != nullptr && !space->IsRegionSpace()) {
CHECK(mark_bitmap != nullptr);
live_bitmap_->AddContinuousSpaceBitmap(live_bitmap);
mark_bitmap_->AddContinuousSpaceBitmap(mark_bitmap);
@@ -1028,7 +1032,7 @@
// Continuous spaces don't necessarily have bitmaps.
accounting::ContinuousSpaceBitmap* live_bitmap = continuous_space->GetLiveBitmap();
accounting::ContinuousSpaceBitmap* mark_bitmap = continuous_space->GetMarkBitmap();
- if (live_bitmap != nullptr) {
+ if (live_bitmap != nullptr && !space->IsRegionSpace()) {
DCHECK(mark_bitmap != nullptr);
live_bitmap_->RemoveContinuousSpaceBitmap(live_bitmap);
mark_bitmap_->RemoveContinuousSpaceBitmap(mark_bitmap);
@@ -1384,6 +1388,7 @@
// Ensure there is only one GC at a time.
WaitForGcToCompleteLocked(cause, self);
collector_type_running_ = collector_type;
+ thread_running_gc_ = self;
}
void Heap::TrimSpaces(Thread* self) {
@@ -2783,6 +2788,7 @@
}
// Reset.
running_collection_is_blocking_ = false;
+ thread_running_gc_ = nullptr;
// Wake anyone who may have been waiting for the GC to complete.
gc_complete_cond_->Broadcast(self);
}
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index a4d300b..0d56213 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -736,7 +736,9 @@
bool IsMovingGCDisabled(Thread* self) REQUIRES(!*gc_complete_lock_) {
MutexLock mu(self, *gc_complete_lock_);
- return disable_moving_gc_count_ > 0;
+ // If we are in a GC critical section or the disable moving GC count is non zero then moving
+ // GC is guaranteed to not start.
+ return disable_moving_gc_count_ > 0 || thread_running_gc_ == self;
}
// Request an asynchronous trim.
@@ -1189,6 +1191,9 @@
// True while the garbage collector is running.
volatile CollectorType collector_type_running_ GUARDED_BY(gc_complete_lock_);
+ // The thread currently running the GC.
+ volatile Thread* thread_running_gc_ GUARDED_BY(gc_complete_lock_);
+
// Last Gc type we ran. Used by WaitForConcurrentGc to know which Gc was waited on.
volatile collector::GcType last_gc_type_ GUARDED_BY(gc_complete_lock_);
collector::GcType next_gc_type_;
diff --git a/runtime/hprof/hprof.cc b/runtime/hprof/hprof.cc
index 133502e..e59c4bb 100644
--- a/runtime/hprof/hprof.cc
+++ b/runtime/hprof/hprof.cc
@@ -50,6 +50,7 @@
#include "gc_root.h"
#include "gc/accounting/heap_bitmap.h"
#include "gc/allocation_record.h"
+#include "gc/scoped_gc_critical_section.h"
#include "gc/heap.h"
#include "gc/space/space.h"
#include "globals.h"
@@ -463,6 +464,7 @@
}
bool okay;
+ visited_objects_.clear();
if (direct_to_ddms_) {
if (kDirectStream) {
okay = DumpToDdmsDirect(overall_size, max_length, CHUNK_TYPE("HPDS"));
@@ -911,6 +913,9 @@
// bits.
std::unordered_set<uint64_t> simple_roots_;
+ // To make sure we don't dump the same object multiple times. b/34967844
+ std::unordered_set<mirror::Object*> visited_objects_;
+
friend class GcRootVisitor;
DISALLOW_COPY_AND_ASSIGN(Hprof);
};
@@ -1093,6 +1098,7 @@
if (obj->IsClass() && obj->AsClass()->IsRetired()) {
return;
}
+ DCHECK(visited_objects_.insert(obj).second) << "Already visited " << obj;
++total_objects_;
@@ -1444,22 +1450,15 @@
// Otherwise, "filename" is used to create an output file.
void DumpHeap(const char* filename, int fd, bool direct_to_ddms) {
CHECK(filename != nullptr);
-
Thread* self = Thread::Current();
- gc::Heap* heap = Runtime::Current()->GetHeap();
- if (heap->IsGcConcurrentAndMoving()) {
- // Need to take a heap dump while GC isn't running. See the
- // comment in Heap::VisitObjects().
- heap->IncrementDisableMovingGC(self);
- }
- {
- ScopedSuspendAll ssa(__FUNCTION__, true /* long suspend */);
- Hprof hprof(filename, fd, direct_to_ddms);
- hprof.Dump();
- }
- if (heap->IsGcConcurrentAndMoving()) {
- heap->DecrementDisableMovingGC(self);
- }
+ // Need to take a heap dump while GC isn't running. See the comment in Heap::VisitObjects().
+ // Also we need the critical section to avoid visiting the same object twice. See b/34967844
+ gc::ScopedGCCriticalSection gcs(self,
+ gc::kGcCauseHprof,
+ gc::kCollectorTypeHprof);
+ ScopedSuspendAll ssa(__FUNCTION__, true /* long suspend */);
+ Hprof hprof(filename, fd, direct_to_ddms);
+ hprof.Dump();
}
} // namespace hprof
diff --git a/runtime/interpreter/unstarted_runtime.cc b/runtime/interpreter/unstarted_runtime.cc
index ae2a978..af0478c 100644
--- a/runtime/interpreter/unstarted_runtime.cc
+++ b/runtime/interpreter/unstarted_runtime.cc
@@ -175,56 +175,61 @@
return param->AsString();
}
-void UnstartedRuntime::UnstartedClassForName(
- Thread* self, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset) {
+void UnstartedRuntime::UnstartedClassForNameCommon(Thread* self,
+ ShadowFrame* shadow_frame,
+ JValue* result,
+ size_t arg_offset,
+ bool long_form,
+ const char* caller) {
mirror::String* class_name = GetClassName(self, shadow_frame, arg_offset);
if (class_name == nullptr) {
return;
}
+ bool initialize_class;
+ mirror::ClassLoader* class_loader;
+ if (long_form) {
+ initialize_class = shadow_frame->GetVReg(arg_offset + 1) != 0;
+ class_loader = down_cast<mirror::ClassLoader*>(shadow_frame->GetVRegReference(arg_offset + 2));
+ } else {
+ initialize_class = true;
+ // TODO: This is really only correct for the boot classpath, and for robustness we should
+ // check the caller.
+ class_loader = nullptr;
+ }
+
+ ScopedObjectAccessUnchecked soa(self);
+ if (class_loader != nullptr && !ClassLinker::IsBootClassLoader(soa, class_loader)) {
+ AbortTransactionOrFail(self,
+ "Only the boot classloader is supported: %s",
+ mirror::Object::PrettyTypeOf(class_loader).c_str());
+ return;
+ }
+
StackHandleScope<1> hs(self);
Handle<mirror::String> h_class_name(hs.NewHandle(class_name));
UnstartedRuntimeFindClass(self,
h_class_name,
ScopedNullHandle<mirror::ClassLoader>(),
result,
- "Class.forName",
- true,
+ caller,
+ initialize_class,
false);
CheckExceptionGenerateClassNotFound(self);
}
+void UnstartedRuntime::UnstartedClassForName(
+ Thread* self, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset) {
+ UnstartedClassForNameCommon(self, shadow_frame, result, arg_offset, false, "Class.forName");
+}
+
void UnstartedRuntime::UnstartedClassForNameLong(
Thread* self, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset) {
- mirror::String* class_name = GetClassName(self, shadow_frame, arg_offset);
- if (class_name == nullptr) {
- return;
- }
- bool initialize_class = shadow_frame->GetVReg(arg_offset + 1) != 0;
- mirror::ClassLoader* class_loader =
- down_cast<mirror::ClassLoader*>(shadow_frame->GetVRegReference(arg_offset + 2));
- StackHandleScope<2> hs(self);
- Handle<mirror::String> h_class_name(hs.NewHandle(class_name));
- Handle<mirror::ClassLoader> h_class_loader(hs.NewHandle(class_loader));
- UnstartedRuntimeFindClass(self, h_class_name, h_class_loader, result, "Class.forName",
- initialize_class, false);
- CheckExceptionGenerateClassNotFound(self);
+ UnstartedClassForNameCommon(self, shadow_frame, result, arg_offset, true, "Class.forName");
}
void UnstartedRuntime::UnstartedClassClassForName(
Thread* self, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset) {
- mirror::String* class_name = GetClassName(self, shadow_frame, arg_offset);
- if (class_name == nullptr) {
- return;
- }
- bool initialize_class = shadow_frame->GetVReg(arg_offset + 1) != 0;
- mirror::ClassLoader* class_loader =
- down_cast<mirror::ClassLoader*>(shadow_frame->GetVRegReference(arg_offset + 2));
- StackHandleScope<2> hs(self);
- Handle<mirror::String> h_class_name(hs.NewHandle(class_name));
- Handle<mirror::ClassLoader> h_class_loader(hs.NewHandle(class_loader));
- UnstartedRuntimeFindClass(self, h_class_name, h_class_loader, result, "Class.classForName",
- initialize_class, false);
- CheckExceptionGenerateClassNotFound(self);
+ UnstartedClassForNameCommon(self, shadow_frame, result, arg_offset, true, "Class.classForName");
}
void UnstartedRuntime::UnstartedClassNewInstance(
@@ -440,6 +445,20 @@
result->SetI(mirror::Class::GetInnerClassFlags(klass, default_value));
}
+void UnstartedRuntime::UnstartedClassGetSignatureAnnotation(
+ Thread* self, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset) {
+ StackHandleScope<1> hs(self);
+ Handle<mirror::Class> klass(hs.NewHandle(
+ reinterpret_cast<mirror::Class*>(shadow_frame->GetVRegReference(arg_offset))));
+
+ if (klass->IsProxyClass() || klass->GetDexCache() == nullptr) {
+ result->SetL(nullptr);
+ return;
+ }
+
+ result->SetL(annotations::GetSignatureAnnotationForClass(klass));
+}
+
void UnstartedRuntime::UnstartedClassIsAnonymousClass(
Thread* self, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset) {
StackHandleScope<1> hs(self);
@@ -613,6 +632,72 @@
GetResourceAsStream(self, shadow_frame, result, arg_offset);
}
+void UnstartedRuntime::UnstartedConstructorNewInstance0(
+ Thread* self, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset) {
+ // This is a cutdown version of java_lang_reflect_Constructor.cc's implementation.
+ StackHandleScope<4> hs(self);
+ Handle<mirror::Constructor> m = hs.NewHandle(
+ reinterpret_cast<mirror::Constructor*>(shadow_frame->GetVRegReference(arg_offset)));
+ Handle<mirror::ObjectArray<mirror::Object>> args = hs.NewHandle(
+ reinterpret_cast<mirror::ObjectArray<mirror::Object>*>(
+ shadow_frame->GetVRegReference(arg_offset + 1)));
+ Handle<mirror::Class> c(hs.NewHandle(m->GetDeclaringClass()));
+ if (UNLIKELY(c->IsAbstract())) {
+ AbortTransactionOrFail(self, "Cannot handle abstract classes");
+ return;
+ }
+ // Verify that we can access the class.
+ if (!m->IsAccessible() && !c->IsPublic()) {
+ // Go 2 frames back, this method is always called from newInstance0, which is called from
+ // Constructor.newInstance(Object... args).
+ ObjPtr<mirror::Class> caller = GetCallingClass(self, 2);
+ // If caller is null, then we called from JNI, just avoid the check since JNI avoids most
+ // access checks anyways. TODO: Investigate if this the correct behavior.
+ if (caller != nullptr && !caller->CanAccess(c.Get())) {
+ AbortTransactionOrFail(self, "Cannot access class");
+ return;
+ }
+ }
+ if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(self, c, true, true)) {
+ DCHECK(self->IsExceptionPending());
+ return;
+ }
+ if (c->IsClassClass()) {
+ AbortTransactionOrFail(self, "new Class() is not supported");
+ return;
+ }
+
+ // String constructor is replaced by a StringFactory method in InvokeMethod.
+ if (c->IsStringClass()) {
+ // We don't support strings.
+ AbortTransactionOrFail(self, "String construction is not supported");
+ return;
+ }
+
+ Handle<mirror::Object> receiver = hs.NewHandle(c->AllocObject(self));
+ if (receiver == nullptr) {
+ AbortTransactionOrFail(self, "Could not allocate");
+ return;
+ }
+
+ // It's easier to use reflection to make the call, than create the uint32_t array.
+ {
+ ScopedObjectAccessUnchecked soa(self);
+ ScopedLocalRef<jobject> method_ref(self->GetJniEnv(),
+ soa.AddLocalReference<jobject>(m.Get()));
+ ScopedLocalRef<jobject> object_ref(self->GetJniEnv(),
+ soa.AddLocalReference<jobject>(receiver.Get()));
+ ScopedLocalRef<jobject> args_ref(self->GetJniEnv(),
+ soa.AddLocalReference<jobject>(args.Get()));
+ InvokeMethod(soa, method_ref.get(), object_ref.get(), args_ref.get(), 2);
+ }
+ if (self->IsExceptionPending()) {
+ AbortTransactionOrFail(self, "Failed running constructor");
+ } else {
+ result->SetL(receiver.Get());
+ }
+}
+
void UnstartedRuntime::UnstartedVmClassLoaderFindLoadedClass(
Thread* self, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset) {
mirror::String* class_name = shadow_frame->GetVRegReference(arg_offset + 1)->AsString();
@@ -897,13 +982,11 @@
REQUIRES_SHARED(Locks::mutator_lock_) {
for (const std::string& allowed_caller : allowed_call_stack) {
if (shadow_frame->GetLink() == nullptr) {
- LOG(ERROR) << "Link is unexpectedly null";
return false;
}
std::string found_caller = ArtMethod::PrettyMethod(shadow_frame->GetLink()->GetMethod());
if (allowed_caller != found_caller) {
- LOG(ERROR) << "Non-match: " << allowed_caller << " vs " << found_caller;
return false;
}
diff --git a/runtime/interpreter/unstarted_runtime.h b/runtime/interpreter/unstarted_runtime.h
index 3f36a27..bc9ead8 100644
--- a/runtime/interpreter/unstarted_runtime.h
+++ b/runtime/interpreter/unstarted_runtime.h
@@ -89,6 +89,13 @@
#undef UNSTARTED_RUNTIME_JNI_LIST
#undef UNSTARTED_JNI
+ static void UnstartedClassForNameCommon(Thread* self,
+ ShadowFrame* shadow_frame,
+ JValue* result,
+ size_t arg_offset,
+ bool long_form,
+ const char* caller) REQUIRES_SHARED(Locks::mutator_lock_);
+
static void InitializeInvokeHandlers();
static void InitializeJNIHandlers();
diff --git a/runtime/interpreter/unstarted_runtime_list.h b/runtime/interpreter/unstarted_runtime_list.h
index 929b747..6fc7989 100644
--- a/runtime/interpreter/unstarted_runtime_list.h
+++ b/runtime/interpreter/unstarted_runtime_list.h
@@ -31,8 +31,10 @@
V(ClassGetDeclaringClass, "java.lang.Class java.lang.Class.getDeclaringClass()") \
V(ClassGetEnclosingClass, "java.lang.Class java.lang.Class.getEnclosingClass()") \
V(ClassGetInnerClassFlags, "int java.lang.Class.getInnerClassFlags(int)") \
+ V(ClassGetSignatureAnnotation, "java.lang.String[] java.lang.Class.getSignatureAnnotation()") \
V(ClassIsAnonymousClass, "boolean java.lang.Class.isAnonymousClass()") \
V(ClassLoaderGetResourceAsStream, "java.io.InputStream java.lang.ClassLoader.getResourceAsStream(java.lang.String)") \
+ V(ConstructorNewInstance0, "java.lang.Object java.lang.reflect.Constructor.newInstance0(java.lang.Object[])") \
V(VmClassLoaderFindLoadedClass, "java.lang.Class java.lang.VMClassLoader.findLoadedClass(java.lang.ClassLoader, java.lang.String)") \
V(VoidLookupType, "java.lang.Class java.lang.Void.lookupType()") \
V(SystemArraycopy, "void java.lang.System.arraycopy(java.lang.Object, int, java.lang.Object, int, int)") \
diff --git a/runtime/interpreter/unstarted_runtime_test.cc b/runtime/interpreter/unstarted_runtime_test.cc
index 98a17e4..db222fa 100644
--- a/runtime/interpreter/unstarted_runtime_test.cc
+++ b/runtime/interpreter/unstarted_runtime_test.cc
@@ -29,6 +29,8 @@
#include "handle_scope-inl.h"
#include "interpreter/interpreter_common.h"
#include "mirror/class_loader.h"
+#include "mirror/object_array-inl.h"
+#include "mirror/object-inl.h"
#include "mirror/string-inl.h"
#include "runtime.h"
#include "scoped_thread_state_change-inl.h"
@@ -1077,12 +1079,293 @@
StackHandleScope<1> hs(self);
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
Handle<mirror::Class> log_manager_class = hs.NewHandle(
- class_linker->FindClass(self,
- "Ljava/util/logging/LogManager;",
- ScopedNullHandle<mirror::ClassLoader>()));
+ class_linker->FindClass(self,
+ "Ljava/util/logging/LogManager;",
+ ScopedNullHandle<mirror::ClassLoader>()));
ASSERT_TRUE(log_manager_class.Get() != nullptr);
ASSERT_TRUE(class_linker->EnsureInitialized(self, log_manager_class, true, true));
}
+class UnstartedClassForNameTest : public UnstartedRuntimeTest {
+ public:
+ template <typename T>
+ void RunTest(T& runner, bool in_transaction, bool should_succeed) {
+ Thread* self = Thread::Current();
+ ScopedObjectAccess soa(self);
+
+ // Ensure that Class is initialized.
+ {
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ StackHandleScope<1> hs(self);
+ Handle<mirror::Class> h_class = hs.NewHandle(mirror::Class::GetJavaLangClass());
+ CHECK(class_linker->EnsureInitialized(self, h_class, true, true));
+ }
+
+ // A selection of classes from different core classpath components.
+ constexpr const char* kTestCases[] = {
+ "java.net.CookieManager", // From libcore.
+ "dalvik.system.ClassExt", // From libart.
+ };
+
+ if (in_transaction) {
+ // For transaction mode, we cannot load any classes, as the pre-fence initialization of
+ // classes isn't transactional. Load them ahead of time.
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ for (const char* name : kTestCases) {
+ class_linker->FindClass(self,
+ DotToDescriptor(name).c_str(),
+ ScopedNullHandle<mirror::ClassLoader>());
+ CHECK(!self->IsExceptionPending()) << self->GetException()->Dump();
+ }
+ }
+
+ if (!should_succeed) {
+ // Negative test. In general, currentThread should fail (as we should not leak a peer that will
+ // be recreated at runtime).
+ PrepareForAborts();
+ }
+
+ JValue result;
+ ShadowFrame* shadow_frame = ShadowFrame::CreateDeoptimizedFrame(10, nullptr, nullptr, 0);
+
+ for (const char* name : kTestCases) {
+ mirror::String* name_string = mirror::String::AllocFromModifiedUtf8(self, name);
+ CHECK(name_string != nullptr);
+
+ Transaction transaction;
+ if (in_transaction) {
+ Runtime::Current()->EnterTransactionMode(&transaction);
+ }
+ CHECK(!self->IsExceptionPending());
+
+ runner(self, shadow_frame, name_string, &result);
+
+ if (in_transaction) {
+ Runtime::Current()->ExitTransactionMode();
+ }
+
+ if (should_succeed) {
+ CHECK(!self->IsExceptionPending()) << name << " " << self->GetException()->Dump();
+ CHECK(result.GetL() != nullptr) << name;
+ } else {
+ CHECK(self->IsExceptionPending()) << name;
+ if (in_transaction) {
+ ASSERT_TRUE(transaction.IsAborted());
+ }
+ self->ClearException();
+ }
+ }
+
+ ShadowFrame::DeleteDeoptimizedFrame(shadow_frame);
+ }
+
+ mirror::ClassLoader* GetBootClassLoader() REQUIRES_SHARED(Locks::mutator_lock_) {
+ Thread* self = Thread::Current();
+ StackHandleScope<2> hs(self);
+ MutableHandle<mirror::ClassLoader> boot_cp = hs.NewHandle<mirror::ClassLoader>(nullptr);
+
+ {
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+
+ // Create the fake boot classloader. Any instance is fine, they are technically interchangeable.
+ Handle<mirror::Class> boot_cp_class = hs.NewHandle(
+ class_linker->FindClass(self,
+ "Ljava/lang/BootClassLoader;",
+ ScopedNullHandle<mirror::ClassLoader>()));
+ CHECK(boot_cp_class != nullptr);
+ CHECK(class_linker->EnsureInitialized(self, boot_cp_class, true, true));
+
+ boot_cp.Assign(boot_cp_class->AllocObject(self)->AsClassLoader());
+ CHECK(boot_cp != nullptr);
+
+ ArtMethod* boot_cp_init = boot_cp_class->FindDeclaredDirectMethod(
+ "<init>", "()V", class_linker->GetImagePointerSize());
+ CHECK(boot_cp_init != nullptr);
+
+ JValue result;
+ ShadowFrame* shadow_frame = ShadowFrame::CreateDeoptimizedFrame(10, nullptr, boot_cp_init, 0);
+ shadow_frame->SetVRegReference(0, boot_cp.Get());
+
+ // create instruction data for invoke-direct {v0} of method with fake index
+ uint16_t inst_data[3] = { 0x1070, 0x0000, 0x0010 };
+ const Instruction* inst = Instruction::At(inst_data);
+
+ interpreter::DoCall<false, false>(boot_cp_init,
+ self,
+ *shadow_frame,
+ inst,
+ inst_data[0],
+ &result);
+ CHECK(!self->IsExceptionPending());
+
+ ShadowFrame::DeleteDeoptimizedFrame(shadow_frame);
+ }
+
+ return boot_cp.Get();
+ }
+};
+
+TEST_F(UnstartedClassForNameTest, ClassForName) {
+ auto runner = [](Thread* self, ShadowFrame* shadow_frame, mirror::String* name, JValue* result)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ shadow_frame->SetVRegReference(0, name);
+ UnstartedClassForName(self, shadow_frame, result, 0);
+ };
+ RunTest(runner, false, true);
+}
+
+TEST_F(UnstartedClassForNameTest, ClassForNameLong) {
+ auto runner = [](Thread* self, ShadowFrame* shadow_frame, mirror::String* name, JValue* result)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ shadow_frame->SetVRegReference(0, name);
+ shadow_frame->SetVReg(1, 0);
+ shadow_frame->SetVRegReference(2, nullptr);
+ UnstartedClassForNameLong(self, shadow_frame, result, 0);
+ };
+ RunTest(runner, false, true);
+}
+
+TEST_F(UnstartedClassForNameTest, ClassForNameLongWithClassLoader) {
+ Thread* self = Thread::Current();
+ ScopedObjectAccess soa(self);
+
+ StackHandleScope<1> hs(self);
+ Handle<mirror::ClassLoader> boot_cp = hs.NewHandle(GetBootClassLoader());
+
+ auto runner = [&](Thread* th, ShadowFrame* shadow_frame, mirror::String* name, JValue* result)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ shadow_frame->SetVRegReference(0, name);
+ shadow_frame->SetVReg(1, 0);
+ shadow_frame->SetVRegReference(2, boot_cp.Get());
+ UnstartedClassForNameLong(th, shadow_frame, result, 0);
+ };
+ RunTest(runner, false, true);
+}
+
+TEST_F(UnstartedClassForNameTest, ClassForNameLongWithClassLoaderTransaction) {
+ Thread* self = Thread::Current();
+ ScopedObjectAccess soa(self);
+
+ StackHandleScope<1> hs(self);
+ Handle<mirror::ClassLoader> boot_cp = hs.NewHandle(GetBootClassLoader());
+
+ auto runner = [&](Thread* th, ShadowFrame* shadow_frame, mirror::String* name, JValue* result)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ shadow_frame->SetVRegReference(0, name);
+ shadow_frame->SetVReg(1, 0);
+ shadow_frame->SetVRegReference(2, boot_cp.Get());
+ UnstartedClassForNameLong(th, shadow_frame, result, 0);
+ };
+ RunTest(runner, true, true);
+}
+
+TEST_F(UnstartedClassForNameTest, ClassForNameLongWithClassLoaderFail) {
+ Thread* self = Thread::Current();
+ ScopedObjectAccess soa(self);
+
+ StackHandleScope<2> hs(self);
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ jobject path_jobj = class_linker->CreatePathClassLoader(self, {});
+ ASSERT_TRUE(path_jobj != nullptr);
+ Handle<mirror::ClassLoader> path_cp = hs.NewHandle<mirror::ClassLoader>(
+ self->DecodeJObject(path_jobj)->AsClassLoader());
+
+ auto runner = [&](Thread* th, ShadowFrame* shadow_frame, mirror::String* name, JValue* result)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ shadow_frame->SetVRegReference(0, name);
+ shadow_frame->SetVReg(1, 0);
+ shadow_frame->SetVRegReference(2, path_cp.Get());
+ UnstartedClassForNameLong(th, shadow_frame, result, 0);
+ };
+ RunTest(runner, true, false);
+}
+
+TEST_F(UnstartedRuntimeTest, ClassGetSignatureAnnotation) {
+ Thread* self = Thread::Current();
+ ScopedObjectAccess soa(self);
+
+ StackHandleScope<1> hs(self);
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ Handle<mirror::Class> list_class = hs.NewHandle(
+ class_linker->FindClass(self,
+ "Ljava/util/List;",
+ ScopedNullHandle<mirror::ClassLoader>()));
+ ASSERT_TRUE(list_class.Get() != nullptr);
+ ASSERT_TRUE(class_linker->EnsureInitialized(self, list_class, true, true));
+
+ JValue result;
+ ShadowFrame* shadow_frame = ShadowFrame::CreateDeoptimizedFrame(10, nullptr, nullptr, 0);
+
+ shadow_frame->SetVRegReference(0, list_class.Get());
+ UnstartedClassGetSignatureAnnotation(self, shadow_frame, &result, 0);
+ ASSERT_TRUE(result.GetL() != nullptr);
+ ASSERT_FALSE(self->IsExceptionPending());
+
+ ShadowFrame::DeleteDeoptimizedFrame(shadow_frame);
+
+ ASSERT_TRUE(result.GetL()->IsObjectArray());
+ ObjPtr<mirror::ObjectArray<mirror::Object>> array =
+ result.GetL()->AsObjectArray<mirror::Object>();
+ std::ostringstream oss;
+ for (int32_t i = 0; i != array->GetLength(); ++i) {
+ ObjPtr<mirror::Object> elem = array->Get(i);
+ ASSERT_TRUE(elem != nullptr);
+ ASSERT_TRUE(elem->IsString());
+ oss << elem->AsString()->ToModifiedUtf8();
+ }
+ std::string output_string = oss.str();
+ ASSERT_EQ(output_string, "<E:Ljava/lang/Object;>Ljava/lang/Object;Ljava/util/Collection<TE;>;");
+}
+
+TEST_F(UnstartedRuntimeTest, ConstructorNewInstance0) {
+ Thread* self = Thread::Current();
+ ScopedObjectAccess soa(self);
+
+ StackHandleScope<4> hs(self);
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+
+ // Get Throwable.
+ Handle<mirror::Class> throw_class = hs.NewHandle(mirror::Throwable::GetJavaLangThrowable());
+ ASSERT_TRUE(class_linker->EnsureInitialized(self, throw_class, true, true));
+
+ // Get an input object.
+ Handle<mirror::String> input = hs.NewHandle(mirror::String::AllocFromModifiedUtf8(self, "abd"));
+
+ // Find the constructor.
+ ArtMethod* throw_cons = throw_class->FindDeclaredDirectMethod(
+ "<init>", "(Ljava/lang/String;)V", class_linker->GetImagePointerSize());
+ ASSERT_TRUE(throw_cons != nullptr);
+
+ Handle<mirror::Constructor> cons = hs.NewHandle(
+ mirror::Constructor::CreateFromArtMethod<kRuntimePointerSize, false>(self, throw_cons));
+ ASSERT_TRUE(cons != nullptr);
+
+ Handle<mirror::ObjectArray<mirror::Object>> args = hs.NewHandle(
+ class_linker->AllocObjectArray<mirror::Object>(self, 1));
+ ASSERT_TRUE(args != nullptr);
+ args->Set(0, input.Get());
+
+ // OK, we're ready now.
+ JValue result;
+ ShadowFrame* shadow_frame = ShadowFrame::CreateDeoptimizedFrame(10, nullptr, nullptr, 0);
+ shadow_frame->SetVRegReference(0, cons.Get());
+ shadow_frame->SetVRegReference(1, args.Get());
+ UnstartedConstructorNewInstance0(self, shadow_frame, &result, 0);
+
+ ASSERT_TRUE(result.GetL() != nullptr);
+ ASSERT_FALSE(self->IsExceptionPending());
+
+ // Should be a new object.
+ ASSERT_NE(result.GetL(), input.Get());
+ // Should be a String.
+ ASSERT_EQ(mirror::Throwable::GetJavaLangThrowable(), result.GetL()->GetClass());
+ // Should have the right string.
+ ObjPtr<mirror::String> result_msg =
+ reinterpret_cast<mirror::Throwable*>(result.GetL())->GetDetailMessage();
+ EXPECT_EQ(input.Get(), result_msg.Ptr());
+
+ ShadowFrame::DeleteDeoptimizedFrame(shadow_frame);
+}
+
} // namespace interpreter
} // namespace art
diff --git a/runtime/method_handles.cc b/runtime/method_handles.cc
index 6ecfd8c..58c5d17 100644
--- a/runtime/method_handles.cc
+++ b/runtime/method_handles.cc
@@ -419,6 +419,32 @@
JValue* result,
const mirror::MethodHandle::Kind handle_kind)
REQUIRES_SHARED(Locks::mutator_lock_) {
+ // For virtual and interface methods ensure called_method points to
+ // the actual method to invoke.
+ if (handle_kind == mirror::MethodHandle::Kind::kInvokeVirtual ||
+ handle_kind == mirror::MethodHandle::Kind::kInvokeInterface) {
+ uint32_t receiver_reg = is_range ? first_arg : args[0];
+ ObjPtr<mirror::Object> receiver(shadow_frame.GetVRegReference(receiver_reg));
+ if (IsCallerTransformer(callsite_type)) {
+ // The current receiver is an emulated stack frame, the method's
+ // receiver needs to be fetched from there as the emulated frame
+ // will be unpacked into a new frame.
+ receiver = ObjPtr<mirror::EmulatedStackFrame>::DownCast(receiver)->GetReceiver();
+ }
+
+ ObjPtr<mirror::Class> declaring_class(called_method->GetDeclaringClass());
+ if (receiver == nullptr || receiver->GetClass() != declaring_class) {
+ // Verify that _vRegC is an object reference and of the type expected by
+ // the receiver.
+ if (!VerifyObjectIsClass(receiver, declaring_class)) {
+ DCHECK(self->IsExceptionPending());
+ return false;
+ }
+ called_method = receiver->GetClass()->FindVirtualMethodForVirtualOrInterface(
+ called_method, kRuntimePointerSize);
+ }
+ }
+
// Compute method information.
const DexFile::CodeItem* code_item = called_method->GetCodeItem();
@@ -502,24 +528,6 @@
}
}
- // See TODO in DoInvokePolymorphic : We need to perform this dynamic, receiver
- // based dispatch right before we perform the actual call, because the
- // receiver isn't known very early.
- if (handle_kind == mirror::MethodHandle::Kind::kInvokeVirtual ||
- handle_kind == mirror::MethodHandle::Kind::kInvokeInterface) {
- ObjPtr<mirror::Object> receiver(new_shadow_frame->GetVRegReference(first_dest_reg));
- ObjPtr<mirror::Class> declaring_class(called_method->GetDeclaringClass());
- // Verify that _vRegC is an object reference and of the type expected by
- // the receiver.
- if (!VerifyObjectIsClass(receiver, declaring_class)) {
- DCHECK(self->IsExceptionPending());
- return false;
- }
-
- called_method = receiver->GetClass()->FindVirtualMethodForVirtualOrInterface(
- called_method, kRuntimePointerSize);
- }
-
PerformCall(self, code_item, shadow_frame.GetMethod(), first_dest_reg, new_shadow_frame, result);
if (self->IsExceptionPending()) {
return false;
diff --git a/runtime/mirror/emulated_stack_frame.h b/runtime/mirror/emulated_stack_frame.h
index ddd84a1..76859ef 100644
--- a/runtime/mirror/emulated_stack_frame.h
+++ b/runtime/mirror/emulated_stack_frame.h
@@ -62,6 +62,10 @@
return GetFieldObject<MethodType>(OFFSET_OF_OBJECT_MEMBER(EmulatedStackFrame, type_));
}
+ mirror::Object* GetReceiver() REQUIRES_SHARED(Locks::mutator_lock_) {
+ return GetReferences()->Get(0);
+ }
+
static void SetClass(Class* klass) REQUIRES_SHARED(Locks::mutator_lock_);
static void ResetClass() REQUIRES_SHARED(Locks::mutator_lock_);
static void VisitRoots(RootVisitor* visitor) REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc
index 1234933..0e61cf6 100644
--- a/runtime/native/dalvik_system_DexFile.cc
+++ b/runtime/native/dalvik_system_DexFile.cc
@@ -155,6 +155,105 @@
void operator=(const NullableScopedUtfChars&);
};
+static std::unique_ptr<MemMap> AllocateDexMemoryMap(JNIEnv* env, jint start, jint end) {
+ if (end <= start) {
+ ScopedObjectAccess soa(env);
+ ThrowWrappedIOException("Bad range");
+ return nullptr;
+ }
+
+ std::string error_message;
+ size_t length = static_cast<size_t>(end - start);
+ std::unique_ptr<MemMap> dex_mem_map(MemMap::MapAnonymous("DEX data",
+ nullptr,
+ length,
+ PROT_READ | PROT_WRITE,
+ /* low_4gb */ false,
+ /* reuse */ false,
+ &error_message));
+ if (dex_mem_map == nullptr) {
+ ScopedObjectAccess soa(env);
+ ThrowWrappedIOException("%s", error_message.c_str());
+ }
+ return dex_mem_map;
+}
+
+static const DexFile* CreateDexFile(JNIEnv* env, std::unique_ptr<MemMap> dex_mem_map) {
+ std::string location = StringPrintf("Anonymous-DexFile@%p-%p",
+ dex_mem_map->Begin(),
+ dex_mem_map->End());
+ std::string error_message;
+ std::unique_ptr<const DexFile> dex_file(DexFile::Open(location,
+ 0,
+ std::move(dex_mem_map),
+ /* verify */ true,
+ /* verify_location */ true,
+ &error_message));
+ if (dex_file == nullptr) {
+ ScopedObjectAccess soa(env);
+ ThrowWrappedIOException("%s", error_message.c_str());
+ return nullptr;
+ }
+
+ if (!dex_file->DisableWrite()) {
+ ScopedObjectAccess soa(env);
+ ThrowWrappedIOException("Failed to make dex file read-only");
+ return nullptr;
+ }
+
+ return dex_file.release();
+}
+
+static jobject CreateSingleDexFileCookie(JNIEnv* env, std::unique_ptr<MemMap> data) {
+ std::unique_ptr<const DexFile> dex_file(CreateDexFile(env, std::move(data)));
+ if (dex_file.get() == nullptr) {
+ DCHECK(env->ExceptionCheck());
+ return nullptr;
+ }
+ std::vector<std::unique_ptr<const DexFile>> dex_files;
+ dex_files.push_back(std::move(dex_file));
+ return ConvertDexFilesToJavaArray(env, nullptr, dex_files);
+}
+
+static jobject DexFile_createCookieWithDirectBuffer(JNIEnv* env,
+ jclass,
+ jobject buffer,
+ jint start,
+ jint end) {
+ uint8_t* base_address = reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(buffer));
+ if (base_address == nullptr) {
+ ScopedObjectAccess soa(env);
+ ThrowWrappedIOException("dexFileBuffer not direct");
+ return 0;
+ }
+
+ std::unique_ptr<MemMap> dex_mem_map(AllocateDexMemoryMap(env, start, end));
+ if (dex_mem_map == nullptr) {
+ DCHECK(Thread::Current()->IsExceptionPending());
+ return 0;
+ }
+
+ size_t length = static_cast<size_t>(end - start);
+ memcpy(dex_mem_map->Begin(), base_address, length);
+ return CreateSingleDexFileCookie(env, std::move(dex_mem_map));
+}
+
+static jobject DexFile_createCookieWithArray(JNIEnv* env,
+ jclass,
+ jbyteArray buffer,
+ jint start,
+ jint end) {
+ std::unique_ptr<MemMap> dex_mem_map(AllocateDexMemoryMap(env, start, end));
+ if (dex_mem_map == nullptr) {
+ DCHECK(Thread::Current()->IsExceptionPending());
+ return 0;
+ }
+
+ auto destination = reinterpret_cast<jbyte*>(dex_mem_map.get()->Begin());
+ env->GetByteArrayRegion(buffer, start, end - start, destination);
+ return CreateSingleDexFileCookie(env, std::move(dex_mem_map));
+}
+
static jobject DexFile_openDexFileNative(JNIEnv* env,
jclass,
jstring javaSourceName,
@@ -591,6 +690,9 @@
"Ljava/lang/ClassLoader;"
"[Ldalvik/system/DexPathList$Element;"
")Ljava/lang/Object;"),
+ NATIVE_METHOD(DexFile, createCookieWithDirectBuffer,
+ "(Ljava/nio/ByteBuffer;II)Ljava/lang/Object;"),
+ NATIVE_METHOD(DexFile, createCookieWithArray, "([BII)Ljava/lang/Object;"),
NATIVE_METHOD(DexFile, isValidCompilerFilter, "(Ljava/lang/String;)Z"),
NATIVE_METHOD(DexFile, isProfileGuidedCompilerFilter, "(Ljava/lang/String;)Z"),
NATIVE_METHOD(DexFile,
diff --git a/runtime/native/dalvik_system_InMemoryDexClassLoader_DexData.cc b/runtime/native/dalvik_system_InMemoryDexClassLoader_DexData.cc
deleted file mode 100644
index 0795960..0000000
--- a/runtime/native/dalvik_system_InMemoryDexClassLoader_DexData.cc
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "dalvik_system_InMemoryDexClassLoader_DexData.h"
-
-#include "android-base/stringprintf.h"
-
-#include "class_linker.h"
-#include "common_throws.h"
-#include "dex_file.h"
-#include "jni_internal.h"
-#include "mem_map.h"
-#include "mirror/class_loader.h"
-#include "mirror/object-inl.h"
-#include "oat_file.h"
-#include "scoped_thread_state_change-inl.h"
-#include "ScopedUtfChars.h"
-
-namespace art {
-
-using android::base::StringPrintf;
-
-static std::unique_ptr<MemMap> AllocateDexMemoryMap(JNIEnv* env, jint start, jint end) {
- if (end <= start) {
- ScopedObjectAccess soa(env);
- ThrowWrappedIOException("Bad range");
- return nullptr;
- }
-
- std::string error_message;
- size_t length = static_cast<size_t>(end - start);
- std::unique_ptr<MemMap> dex_mem_map(MemMap::MapAnonymous("DEX data",
- nullptr,
- length,
- PROT_READ | PROT_WRITE,
- /* low_4gb */ false,
- /* reuse */ false,
- &error_message));
- if (dex_mem_map == nullptr) {
- ScopedObjectAccess soa(env);
- ThrowWrappedIOException("%s", error_message.c_str());
- }
- return dex_mem_map;
-}
-
-static jlong DexFileToCookie(const DexFile* dex_file) {
- return reinterpret_cast<jlong>(dex_file);
-}
-
-static const DexFile* CookieToDexFile(jlong cookie) {
- return reinterpret_cast<const DexFile*>(cookie);
-}
-
-static const DexFile* CreateDexFile(JNIEnv* env, std::unique_ptr<MemMap> dex_mem_map) {
- std::string location = StringPrintf("InMemoryDexClassLoader_DexData@%p-%p",
- dex_mem_map->Begin(),
- dex_mem_map->End());
- std::string error_message;
- std::unique_ptr<const DexFile> dex_file(DexFile::Open(location,
- 0,
- std::move(dex_mem_map),
- /* verify */ true,
- /* verify_location */ true,
- &error_message));
- if (dex_file == nullptr) {
- ScopedObjectAccess soa(env);
- ThrowWrappedIOException("%s", error_message.c_str());
- return nullptr;
- }
-
- if (!dex_file->DisableWrite()) {
- ScopedObjectAccess soa(env);
- ThrowWrappedIOException("Failed to make dex file read-only");
- return nullptr;
- }
-
- return dex_file.release();
-}
-
-static jlong InMemoryDexClassLoader_DexData_initializeWithDirectBuffer(
- JNIEnv* env, jclass, jobject buffer, jint start, jint end) {
- uint8_t* base_address = reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(buffer));
- if (base_address == nullptr) {
- ScopedObjectAccess soa(env);
- ThrowWrappedIOException("dexFileBuffer not direct");
- return 0;
- }
-
- std::unique_ptr<MemMap> dex_mem_map(AllocateDexMemoryMap(env, start, end));
- if (dex_mem_map == nullptr) {
- DCHECK(Thread::Current()->IsExceptionPending());
- return 0;
- }
-
- size_t length = static_cast<size_t>(end - start);
- memcpy(dex_mem_map->Begin(), base_address, length);
- return DexFileToCookie(CreateDexFile(env, std::move(dex_mem_map)));
-}
-
-static jlong InMemoryDexClassLoader_DexData_initializeWithArray(
- JNIEnv* env, jclass, jbyteArray buffer, jint start, jint end) {
- std::unique_ptr<MemMap> dex_mem_map(AllocateDexMemoryMap(env, start, end));
- if (dex_mem_map == nullptr) {
- DCHECK(Thread::Current()->IsExceptionPending());
- return 0;
- }
-
- auto destination = reinterpret_cast<jbyte*>(dex_mem_map.get()->Begin());
- env->GetByteArrayRegion(buffer, start, end - start, destination);
- return DexFileToCookie(CreateDexFile(env, std::move(dex_mem_map)));
-}
-
-static void InMemoryDexClassLoader_DexData_uninitialize(JNIEnv* env, jclass, jlong cookie) {
- const DexFile* dex_file = CookieToDexFile(cookie);
- if (kIsDebugBuild) {
- ScopedObjectAccess soa(env);
- ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
- CHECK(!class_linker->IsDexFileRegistered(soa.Self(), *dex_file));
- }
- delete dex_file;
-}
-
-static jclass InMemoryDexClassLoader_DexData_findClass(
- JNIEnv* env, jobject dexData, jstring name, jobject loader, jlong cookie) {
- ScopedUtfChars scoped_class_name(env, name);
- if (env->ExceptionCheck()) {
- return nullptr;
- }
-
- const char* class_name = scoped_class_name.c_str();
- const std::string descriptor(DotToDescriptor(class_name));
- const char* class_descriptor = descriptor.c_str();
- const size_t hash = ComputeModifiedUtf8Hash(class_descriptor);
- const DexFile* dex_file = CookieToDexFile(cookie);
- const DexFile::ClassDef* dex_class_def =
- OatDexFile::FindClassDef(*dex_file, class_descriptor, hash);
- if (dex_class_def != nullptr) {
- ScopedObjectAccess soa(env);
- ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- StackHandleScope<1> handle_scope(soa.Self());
- Handle<mirror::ClassLoader> class_loader(
- handle_scope.NewHandle(soa.Decode<mirror::ClassLoader>(loader)));
- ObjPtr<mirror::DexCache> dex_cache =
- class_linker->RegisterDexFile(*dex_file, class_loader.Get());
- if (dex_cache == nullptr) {
- // OOME or InternalError (dexFile already registered with a different class loader).
- soa.Self()->AssertPendingException();
- return nullptr;
- }
- ObjPtr<mirror::Class> result = class_linker->DefineClass(
- soa.Self(),
- class_descriptor,
- hash, class_loader,
- *dex_file,
- *dex_class_def);
- if (result != nullptr) {
- // Ensure the class table has a strong reference to the
- // InMemoryClassLoader/DexData instance now that a class has
- // been loaded.
- class_linker->InsertDexFileInToClassLoader(soa.Decode<mirror::Object>(dexData),
- class_loader.Get());
- return soa.AddLocalReference<jclass>(result);
- }
- }
-
- VLOG(class_linker) << "Failed to find dex_class_def " << class_name;
- return nullptr;
-}
-
-static JNINativeMethod gMethods[] = {
- NATIVE_METHOD(InMemoryDexClassLoader_DexData,
- initializeWithDirectBuffer,
- "(Ljava/nio/ByteBuffer;II)J"),
- NATIVE_METHOD(InMemoryDexClassLoader_DexData, initializeWithArray, "([BII)J"),
- NATIVE_METHOD(InMemoryDexClassLoader_DexData, uninitialize, "(J)V"),
- NATIVE_METHOD(InMemoryDexClassLoader_DexData,
- findClass,
- "(Ljava/lang/String;Ljava/lang/ClassLoader;J)Ljava/lang/Class;"),
-};
-
-void register_dalvik_system_InMemoryDexClassLoader_DexData(JNIEnv* env) {
- REGISTER_NATIVE_METHODS("dalvik/system/InMemoryDexClassLoader$DexData");
-}
-
-} // namespace art
diff --git a/runtime/native/dalvik_system_InMemoryDexClassLoader_DexData.h b/runtime/native/dalvik_system_InMemoryDexClassLoader_DexData.h
deleted file mode 100644
index f73d07a..0000000
--- a/runtime/native/dalvik_system_InMemoryDexClassLoader_DexData.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_RUNTIME_NATIVE_DALVIK_SYSTEM_INMEMORYDEXCLASSLOADER_DEXDATA_H_
-#define ART_RUNTIME_NATIVE_DALVIK_SYSTEM_INMEMORYDEXCLASSLOADER_DEXDATA_H_
-
-#include <jni.h>
-
-namespace art {
-
-void register_dalvik_system_InMemoryDexClassLoader_DexData(JNIEnv* env);
-
-} // namespace art
-
-#endif // ART_RUNTIME_NATIVE_DALVIK_SYSTEM_INMEMORYDEXCLASSLOADER_DEXDATA_H_
diff --git a/runtime/oat.h b/runtime/oat.h
index 0f6657b..656b868 100644
--- a/runtime/oat.h
+++ b/runtime/oat.h
@@ -32,7 +32,7 @@
class PACKED(4) OatHeader {
public:
static constexpr uint8_t kOatMagic[] = { 'o', 'a', 't', '\n' };
- static constexpr uint8_t kOatVersion[] = { '1', '1', '2', '\0' }; // Manual bump (Revert^3 hash-based DexCache types; stack maps).
+ static constexpr uint8_t kOatVersion[] = { '1', '1', '3', '\0' }; // Invoke info change.
static constexpr const char* kImageLocationKey = "image-location";
static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline";
diff --git a/runtime/openjdkjvmti/ti_class.cc b/runtime/openjdkjvmti/ti_class.cc
index 7ca233f..a8a0ded 100644
--- a/runtime/openjdkjvmti/ti_class.cc
+++ b/runtime/openjdkjvmti/ti_class.cc
@@ -41,6 +41,7 @@
#include "class_table-inl.h"
#include "class_linker.h"
#include "common_throws.h"
+#include "dex_file_annotations.h"
#include "events-inl.h"
#include "gc/heap.h"
#include "gc_root.h"
@@ -50,6 +51,7 @@
#include "mirror/array-inl.h"
#include "mirror/class-inl.h"
#include "mirror/class_ext.h"
+#include "mirror/object_array-inl.h"
#include "mirror/object_reference.h"
#include "mirror/object-inl.h"
#include "mirror/reference.h"
@@ -685,9 +687,30 @@
*signature_ptr = reinterpret_cast<char*>(tmp);
}
- // TODO: Support generic signature.
if (generic_ptr != nullptr) {
*generic_ptr = nullptr;
+ if (!klass->IsProxyClass() && klass->GetDexCache() != nullptr) {
+ art::StackHandleScope<1> hs(soa.Self());
+ art::Handle<art::mirror::Class> h_klass = hs.NewHandle(klass);
+ art::mirror::ObjectArray<art::mirror::String>* str_array =
+ art::annotations::GetSignatureAnnotationForClass(h_klass);
+ if (str_array != nullptr) {
+ std::ostringstream oss;
+ for (int32_t i = 0; i != str_array->GetLength(); ++i) {
+ oss << str_array->Get(i)->ToModifiedUtf8();
+ }
+ std::string output_string = oss.str();
+ unsigned char* tmp;
+ jvmtiError ret = CopyString(env, output_string.c_str(), &tmp);
+ if (ret != ERR(NONE)) {
+ return ret;
+ }
+ *generic_ptr = reinterpret_cast<char*>(tmp);
+ } else if (soa.Self()->IsExceptionPending()) {
+ // TODO: Should we report an error here?
+ soa.Self()->ClearException();
+ }
+ }
}
// Everything is fine, release the buffers.
diff --git a/runtime/openjdkjvmti/ti_field.cc b/runtime/openjdkjvmti/ti_field.cc
index a762830..131e6c3 100644
--- a/runtime/openjdkjvmti/ti_field.cc
+++ b/runtime/openjdkjvmti/ti_field.cc
@@ -34,7 +34,9 @@
#include "art_jvmti.h"
#include "art_field-inl.h"
#include "base/enums.h"
+#include "dex_file_annotations.h"
#include "jni_internal.h"
+#include "mirror/object_array-inl.h"
#include "modifiers.h"
#include "scoped_thread_state_change-inl.h"
#include "thread-inl.h"
@@ -91,6 +93,26 @@
// TODO: Support generic signature.
if (generic_ptr != nullptr) {
*generic_ptr = nullptr;
+ if (!art_field->GetDeclaringClass()->IsProxyClass()) {
+ art::mirror::ObjectArray<art::mirror::String>* str_array =
+ art::annotations::GetSignatureAnnotationForField(art_field);
+ if (str_array != nullptr) {
+ std::ostringstream oss;
+ for (int32_t i = 0; i != str_array->GetLength(); ++i) {
+ oss << str_array->Get(i)->ToModifiedUtf8();
+ }
+ std::string output_string = oss.str();
+ unsigned char* tmp;
+ jvmtiError ret = CopyString(env, output_string.c_str(), &tmp);
+ if (ret != ERR(NONE)) {
+ return ret;
+ }
+ *generic_ptr = reinterpret_cast<char*>(tmp);
+ } else if (soa.Self()->IsExceptionPending()) {
+ // TODO: Should we report an error here?
+ soa.Self()->ClearException();
+ }
+ }
}
// Everything is fine, release the buffers.
diff --git a/runtime/openjdkjvmti/ti_method.cc b/runtime/openjdkjvmti/ti_method.cc
index 2ddd64a..a6cfcc1 100644
--- a/runtime/openjdkjvmti/ti_method.cc
+++ b/runtime/openjdkjvmti/ti_method.cc
@@ -34,7 +34,9 @@
#include "art_jvmti.h"
#include "art_method-inl.h"
#include "base/enums.h"
+#include "dex_file_annotations.h"
#include "jni_internal.h"
+#include "mirror/object_array-inl.h"
#include "modifiers.h"
#include "scoped_thread_state_change-inl.h"
#include "thread-inl.h"
@@ -139,6 +141,26 @@
// TODO: Support generic signature.
if (generic_ptr != nullptr) {
*generic_ptr = nullptr;
+ if (!art_method->GetDeclaringClass()->IsProxyClass()) {
+ art::mirror::ObjectArray<art::mirror::String>* str_array =
+ art::annotations::GetSignatureAnnotationForMethod(art_method);
+ if (str_array != nullptr) {
+ std::ostringstream oss;
+ for (int32_t i = 0; i != str_array->GetLength(); ++i) {
+ oss << str_array->Get(i)->ToModifiedUtf8();
+ }
+ std::string output_string = oss.str();
+ unsigned char* tmp;
+ jvmtiError ret = CopyString(env, output_string.c_str(), &tmp);
+ if (ret != ERR(NONE)) {
+ return ret;
+ }
+ *generic_ptr = reinterpret_cast<char*>(tmp);
+ } else if (soa.Self()->IsExceptionPending()) {
+ // TODO: Should we report an error here?
+ soa.Self()->ClearException();
+ }
+ }
}
// Everything is fine, release the buffers.
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index f8f3d76..69dcfeb 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -101,7 +101,6 @@
#include "mirror/throwable.h"
#include "monitor.h"
#include "native/dalvik_system_DexFile.h"
-#include "native/dalvik_system_InMemoryDexClassLoader_DexData.h"
#include "native/dalvik_system_VMDebug.h"
#include "native/dalvik_system_VMRuntime.h"
#include "native/dalvik_system_VMStack.h"
@@ -1534,7 +1533,6 @@
void Runtime::RegisterRuntimeNativeMethods(JNIEnv* env) {
register_dalvik_system_DexFile(env);
- register_dalvik_system_InMemoryDexClassLoader_DexData(env);
register_dalvik_system_VMDebug(env);
register_dalvik_system_VMRuntime(env);
register_dalvik_system_VMStack(env);
diff --git a/runtime/stack_map.h b/runtime/stack_map.h
index f7a6402..67f0b57 100644
--- a/runtime/stack_map.h
+++ b/runtime/stack_map.h
@@ -1145,6 +1145,94 @@
}
};
+// Format is [native pc, invoke type, method index].
+class InvokeInfoEncoding {
+ public:
+ void SetFromSizes(size_t native_pc_max,
+ size_t invoke_type_max,
+ size_t method_index_max) {
+ total_bit_size_ = 0;
+ DCHECK_EQ(kNativePcBitOffset, total_bit_size_);
+ total_bit_size_ += MinimumBitsToStore(native_pc_max);
+ invoke_type_bit_offset_ = total_bit_size_;
+ total_bit_size_ += MinimumBitsToStore(invoke_type_max);
+ method_index_bit_offset_ = total_bit_size_;
+ total_bit_size_ += MinimumBitsToStore(method_index_max);
+ }
+
+ ALWAYS_INLINE FieldEncoding GetNativePcEncoding() const {
+ return FieldEncoding(kNativePcBitOffset, invoke_type_bit_offset_);
+ }
+
+ ALWAYS_INLINE FieldEncoding GetInvokeTypeEncoding() const {
+ return FieldEncoding(invoke_type_bit_offset_, method_index_bit_offset_);
+ }
+
+ ALWAYS_INLINE FieldEncoding GetMethodIndexEncoding() const {
+ return FieldEncoding(method_index_bit_offset_, total_bit_size_);
+ }
+
+ ALWAYS_INLINE size_t BitSize() const {
+ return total_bit_size_;
+ }
+
+ template<typename Vector>
+ void Encode(Vector* dest) const {
+ static_assert(alignof(InvokeInfoEncoding) == 1, "Should not require alignment");
+ const uint8_t* ptr = reinterpret_cast<const uint8_t*>(this);
+ dest->insert(dest->end(), ptr, ptr + sizeof(*this));
+ }
+
+ void Decode(const uint8_t** ptr) {
+ *this = *reinterpret_cast<const InvokeInfoEncoding*>(*ptr);
+ *ptr += sizeof(*this);
+ }
+
+ private:
+ static constexpr uint8_t kNativePcBitOffset = 0;
+ uint8_t invoke_type_bit_offset_;
+ uint8_t method_index_bit_offset_;
+ uint8_t total_bit_size_;
+};
+
+class InvokeInfo {
+ public:
+ explicit InvokeInfo(BitMemoryRegion region) : region_(region) {}
+
+ ALWAYS_INLINE uint32_t GetNativePcOffset(const InvokeInfoEncoding& encoding,
+ InstructionSet instruction_set) const {
+ CodeOffset offset(
+ CodeOffset::FromCompressedOffset(encoding.GetNativePcEncoding().Load(region_)));
+ return offset.Uint32Value(instruction_set);
+ }
+
+ ALWAYS_INLINE void SetNativePcCodeOffset(const InvokeInfoEncoding& encoding,
+ CodeOffset native_pc_offset) {
+ encoding.GetNativePcEncoding().Store(region_, native_pc_offset.CompressedValue());
+ }
+
+ ALWAYS_INLINE uint32_t GetInvokeType(const InvokeInfoEncoding& encoding) const {
+ return encoding.GetInvokeTypeEncoding().Load(region_);
+ }
+
+ ALWAYS_INLINE void SetInvokeType(const InvokeInfoEncoding& encoding, uint32_t invoke_type) {
+ encoding.GetInvokeTypeEncoding().Store(region_, invoke_type);
+ }
+
+ ALWAYS_INLINE uint32_t GetMethodIndex(const InvokeInfoEncoding& encoding) const {
+ return encoding.GetMethodIndexEncoding().Load(region_);
+ }
+
+ ALWAYS_INLINE void SetMethodIndex(const InvokeInfoEncoding& encoding, uint32_t method_index) {
+ encoding.GetMethodIndexEncoding().Store(region_, method_index);
+ }
+
+ bool IsValid() const { return region_.pointer() != nullptr; }
+
+ private:
+ BitMemoryRegion region_;
+};
+
// Most of the fields are encoded as ULEB128 to save space.
struct CodeInfoEncoding {
static constexpr uint32_t kInvalidSize = static_cast<size_t>(-1);
@@ -1154,6 +1242,7 @@
BitEncodingTable<StackMapEncoding> stack_map;
BitEncodingTable<BitRegionEncoding> register_mask;
BitEncodingTable<BitRegionEncoding> stack_mask;
+ BitEncodingTable<InvokeInfoEncoding> invoke_info;
BitEncodingTable<InlineInfoEncoding> inline_info;
CodeInfoEncoding() {}
@@ -1165,6 +1254,7 @@
stack_map.Decode(&ptr);
register_mask.Decode(&ptr);
stack_mask.Decode(&ptr);
+ invoke_info.Decode(&ptr);
if (stack_map.encoding.GetInlineInfoEncoding().BitSize() > 0) {
inline_info.Decode(&ptr);
} else {
@@ -1183,6 +1273,7 @@
stack_map.Encode(dest);
register_mask.Encode(dest);
stack_mask.Encode(dest);
+ invoke_info.Encode(dest);
if (stack_map.encoding.GetInlineInfoEncoding().BitSize() > 0) {
inline_info.Encode(dest);
}
@@ -1199,6 +1290,7 @@
stack_map.UpdateBitOffset(&bit_offset);
register_mask.UpdateBitOffset(&bit_offset);
stack_mask.UpdateBitOffset(&bit_offset);
+ invoke_info.UpdateBitOffset(&bit_offset);
inline_info.UpdateBitOffset(&bit_offset);
cache_non_header_size = RoundUp(bit_offset, kBitsPerByte) / kBitsPerByte - HeaderSize();
}
@@ -1303,6 +1395,10 @@
return encoding.stack_map.encoding.BitSize() * GetNumberOfStackMaps(encoding);
}
+ InvokeInfo GetInvokeInfo(const CodeInfoEncoding& encoding, size_t index) const {
+ return InvokeInfo(encoding.invoke_info.BitRegion(region_, index));
+ }
+
DexRegisterMap GetDexRegisterMapOf(StackMap stack_map,
const CodeInfoEncoding& encoding,
size_t number_of_dex_registers) const {
@@ -1426,6 +1522,17 @@
return StackMap();
}
+ InvokeInfo GetInvokeInfoForNativePcOffset(uint32_t native_pc_offset,
+ const CodeInfoEncoding& encoding) {
+ for (size_t index = 0; index < encoding.invoke_info.num_entries; index++) {
+ InvokeInfo item = GetInvokeInfo(encoding, index);
+ if (item.GetNativePcOffset(encoding.invoke_info.encoding, kRuntimeISA) == native_pc_offset) {
+ return item;
+ }
+ }
+ return InvokeInfo(BitMemoryRegion());
+ }
+
// Dump this CodeInfo object on `os`. `code_offset` is the (absolute)
// native PC of the compiled method and `number_of_dex_registers` the
// number of Dex virtual registers used in this method. If
diff --git a/test/021-string2/src/Main.java b/test/021-string2/src/Main.java
index 5a43a4f..0dd82ab 100644
--- a/test/021-string2/src/Main.java
+++ b/test/021-string2/src/Main.java
@@ -16,6 +16,7 @@
import junit.framework.Assert;
import java.lang.reflect.Method;
+import java.util.Locale;
/**
* more string tests
@@ -120,6 +121,12 @@
testEqualsConstString();
testConstStringEquals();
+
+ // Regression tests for String.setCharAt() breaking string compression invariants.
+ Locale en_US = new Locale("en", "US");
+ Assert.assertEquals("I", /* Small latin dotless i */ "\u0131".toUpperCase());
+ Assert.assertEquals("abc", "a\u0131c".replace('\u0131', 'b'));
+ Assert.assertEquals("a\u0131c", "abc".replace('b', '\u0131'));
}
public static void testCompareToAndEquals() {
diff --git a/test/044-proxy/build b/test/044-proxy/build
deleted file mode 100755
index ab956e2..0000000
--- a/test/044-proxy/build
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# Copyright 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.
-
-./default-build "$@" --experimental java-8
diff --git a/test/624-checker-stringops/src/Main.java b/test/624-checker-stringops/src/Main.java
index 75b782e..63da4f5 100644
--- a/test/624-checker-stringops/src/Main.java
+++ b/test/624-checker-stringops/src/Main.java
@@ -232,8 +232,9 @@
/// CHECK-NOT: InvokeVirtual intrinsic:StringStringIndexOfAfter
static int bufferDeadLoop() {
StringBuffer b = new StringBuffer();
+ String x = "x";
for (int i = 0; i < 10; i++) {
- int d = b.toString().indexOf("x", 1);
+ int d = b.toString().indexOf(x, 1);
}
return b.length();
}
@@ -252,8 +253,9 @@
/// CHECK-NOT: InvokeVirtual intrinsic:StringStringIndexOfAfter
static int builderDeadLoop() {
StringBuilder b = new StringBuilder();
+ String x = "x";
for (int i = 0; i < 10; i++) {
- int d = b.toString().indexOf("x", 1);
+ int d = b.toString().indexOf(x, 1);
}
return b.length();
}
diff --git a/test/900-hello-plugin/build b/test/900-hello-plugin/build
deleted file mode 100755
index 898e2e5..0000000
--- a/test/900-hello-plugin/build
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2016 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.
-
-./default-build "$@" --experimental agents
diff --git a/test/901-hello-ti-agent/build b/test/901-hello-ti-agent/build
deleted file mode 100755
index 898e2e5..0000000
--- a/test/901-hello-ti-agent/build
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2016 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.
-
-./default-build "$@" --experimental agents
diff --git a/test/902-hello-transformation/build b/test/902-hello-transformation/build
deleted file mode 100755
index 898e2e5..0000000
--- a/test/902-hello-transformation/build
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2016 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.
-
-./default-build "$@" --experimental agents
diff --git a/test/903-hello-tagging/build b/test/903-hello-tagging/build
deleted file mode 100755
index 898e2e5..0000000
--- a/test/903-hello-tagging/build
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2016 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.
-
-./default-build "$@" --experimental agents
diff --git a/test/904-object-allocation/build b/test/904-object-allocation/build
deleted file mode 100755
index 898e2e5..0000000
--- a/test/904-object-allocation/build
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2016 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.
-
-./default-build "$@" --experimental agents
diff --git a/test/905-object-free/build b/test/905-object-free/build
deleted file mode 100755
index 898e2e5..0000000
--- a/test/905-object-free/build
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2016 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.
-
-./default-build "$@" --experimental agents
diff --git a/test/906-iterate-heap/build b/test/906-iterate-heap/build
deleted file mode 100755
index 898e2e5..0000000
--- a/test/906-iterate-heap/build
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2016 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.
-
-./default-build "$@" --experimental agents
diff --git a/test/907-get-loaded-classes/build b/test/907-get-loaded-classes/build
deleted file mode 100755
index 898e2e5..0000000
--- a/test/907-get-loaded-classes/build
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2016 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.
-
-./default-build "$@" --experimental agents
diff --git a/test/908-gc-start-finish/build b/test/908-gc-start-finish/build
deleted file mode 100755
index 898e2e5..0000000
--- a/test/908-gc-start-finish/build
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2016 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.
-
-./default-build "$@" --experimental agents
diff --git a/test/909-attach-agent/build b/test/909-attach-agent/build
deleted file mode 100755
index 898e2e5..0000000
--- a/test/909-attach-agent/build
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2016 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.
-
-./default-build "$@" --experimental agents
diff --git a/test/910-methods/build b/test/910-methods/build
deleted file mode 100755
index 898e2e5..0000000
--- a/test/910-methods/build
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2016 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.
-
-./default-build "$@" --experimental agents
diff --git a/test/910-methods/expected.txt b/test/910-methods/expected.txt
index c913b3f..e87929f 100644
--- a/test/910-methods/expected.txt
+++ b/test/910-methods/expected.txt
@@ -28,7 +28,7 @@
Is native: true
Is obsolete: false
Is synthetic: false
-[add, (Ljava/lang/Object;)Z, null]
+[add, (Ljava/lang/Object;)Z, (TE;)Z]
interface java.util.List
1025
Max locals: 0
diff --git a/test/911-get-stack-trace/build b/test/911-get-stack-trace/build
deleted file mode 100755
index 898e2e5..0000000
--- a/test/911-get-stack-trace/build
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2016 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.
-
-./default-build "$@" --experimental agents
diff --git a/test/912-classes/build b/test/912-classes/build
deleted file mode 100755
index 898e2e5..0000000
--- a/test/912-classes/build
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2016 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.
-
-./default-build "$@" --experimental agents
diff --git a/test/912-classes/expected.txt b/test/912-classes/expected.txt
index 328216b..e932b20 100644
--- a/test/912-classes/expected.txt
+++ b/test/912-classes/expected.txt
@@ -1,10 +1,10 @@
[Ljava/lang/Object;, null]
1
-[Ljava/lang/String;, null]
+[Ljava/lang/String;, Ljava/lang/Object;Ljava/io/Serializable;Ljava/lang/Comparable<Ljava/lang/String;>;Ljava/lang/CharSequence;]
11
[Ljava/lang/Math;, null]
11
-[Ljava/util/List;, null]
+[Ljava/util/List;, <E:Ljava/lang/Object;>Ljava/lang/Object;Ljava/util/Collection<TE;>;]
601
[L$Proxy0;, null]
11
diff --git a/test/913-heaps/build b/test/913-heaps/build
deleted file mode 100755
index 898e2e5..0000000
--- a/test/913-heaps/build
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2016 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.
-
-./default-build "$@" --experimental agents
diff --git a/test/914-hello-obsolescence/build b/test/914-hello-obsolescence/build
deleted file mode 100755
index 898e2e5..0000000
--- a/test/914-hello-obsolescence/build
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2016 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.
-
-./default-build "$@" --experimental agents
diff --git a/test/915-obsolete-2/build b/test/915-obsolete-2/build
deleted file mode 100755
index 898e2e5..0000000
--- a/test/915-obsolete-2/build
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2016 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.
-
-./default-build "$@" --experimental agents
diff --git a/test/916-obsolete-jit/build b/test/916-obsolete-jit/build
deleted file mode 100755
index 898e2e5..0000000
--- a/test/916-obsolete-jit/build
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2016 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.
-
-./default-build "$@" --experimental agents
diff --git a/test/917-fields-transformation/build b/test/917-fields-transformation/build
deleted file mode 100755
index 898e2e5..0000000
--- a/test/917-fields-transformation/build
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2016 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.
-
-./default-build "$@" --experimental agents
diff --git a/test/918-fields/build b/test/918-fields/build
deleted file mode 100755
index 898e2e5..0000000
--- a/test/918-fields/build
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2016 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.
-
-./default-build "$@" --experimental agents
diff --git a/test/918-fields/expected.txt b/test/918-fields/expected.txt
index 39d3e70..1a1209c 100644
--- a/test/918-fields/expected.txt
+++ b/test/918-fields/expected.txt
@@ -14,3 +14,7 @@
interface Main$Bar
25
false
+[generics, Ljava/lang/Object;, TT;]
+class Main$Generics
+0
+false
diff --git a/test/918-fields/src/Main.java b/test/918-fields/src/Main.java
index 3ba535b..ad0d0c5 100644
--- a/test/918-fields/src/Main.java
+++ b/test/918-fields/src/Main.java
@@ -27,6 +27,7 @@
testField(Integer.class, "value");
testField(Foo.class, "this$0");
testField(Bar.class, "VAL");
+ testField(Generics.class, "generics");
}
private static void testField(Class<?> base, String fieldName)
@@ -65,4 +66,8 @@
private static interface Bar {
public static int VAL = 1;
}
+
+ private static class Generics<T> {
+ T generics;
+ }
}
diff --git a/test/919-obsolete-fields/build b/test/919-obsolete-fields/build
deleted file mode 100755
index 898e2e5..0000000
--- a/test/919-obsolete-fields/build
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2016 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.
-
-./default-build "$@" --experimental agents
diff --git a/test/920-objects/build b/test/920-objects/build
deleted file mode 100755
index 898e2e5..0000000
--- a/test/920-objects/build
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2016 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.
-
-./default-build "$@" --experimental agents
diff --git a/test/921-hello-failure/build b/test/921-hello-failure/build
deleted file mode 100755
index 898e2e5..0000000
--- a/test/921-hello-failure/build
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2016 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.
-
-./default-build "$@" --experimental agents
diff --git a/test/922-properties/build b/test/922-properties/build
deleted file mode 100755
index 898e2e5..0000000
--- a/test/922-properties/build
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2016 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.
-
-./default-build "$@" --experimental agents
diff --git a/test/923-monitors/build b/test/923-monitors/build
deleted file mode 100755
index 898e2e5..0000000
--- a/test/923-monitors/build
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2016 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.
-
-./default-build "$@" --experimental agents
diff --git a/test/924-threads/build b/test/924-threads/build
deleted file mode 100755
index 898e2e5..0000000
--- a/test/924-threads/build
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2016 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.
-
-./default-build "$@" --experimental agents
diff --git a/test/925-threadgroups/build b/test/925-threadgroups/build
deleted file mode 100755
index 898e2e5..0000000
--- a/test/925-threadgroups/build
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2016 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.
-
-./default-build "$@" --experimental agents
diff --git a/test/926-multi-obsolescence/build b/test/926-multi-obsolescence/build
deleted file mode 100755
index 898e2e5..0000000
--- a/test/926-multi-obsolescence/build
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2016 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.
-
-./default-build "$@" --experimental agents
diff --git a/test/927-timers/build b/test/927-timers/build
deleted file mode 100755
index 898e2e5..0000000
--- a/test/927-timers/build
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2016 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.
-
-./default-build "$@" --experimental agents
diff --git a/test/928-jni-table/build b/test/928-jni-table/build
deleted file mode 100755
index 898e2e5..0000000
--- a/test/928-jni-table/build
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2016 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.
-
-./default-build "$@" --experimental agents
diff --git a/test/929-search/build b/test/929-search/build
deleted file mode 100755
index 898e2e5..0000000
--- a/test/929-search/build
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2016 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.
-
-./default-build "$@" --experimental agents
diff --git a/test/930-hello-retransform/build b/test/930-hello-retransform/build
deleted file mode 100755
index 898e2e5..0000000
--- a/test/930-hello-retransform/build
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2016 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.
-
-./default-build "$@" --experimental agents
diff --git a/test/931-agent-thread/build b/test/931-agent-thread/build
deleted file mode 100755
index 898e2e5..0000000
--- a/test/931-agent-thread/build
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2016 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.
-
-./default-build "$@" --experimental agents
diff --git a/test/932-transform-saves/build b/test/932-transform-saves/build
deleted file mode 100755
index 898e2e5..0000000
--- a/test/932-transform-saves/build
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2016 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.
-
-./default-build "$@" --experimental agents
diff --git a/test/933-misc-events/build b/test/933-misc-events/build
deleted file mode 100755
index 898e2e5..0000000
--- a/test/933-misc-events/build
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2016 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.
-
-./default-build "$@" --experimental agents
diff --git a/test/934-load-transform/build b/test/934-load-transform/build
deleted file mode 100755
index 898e2e5..0000000
--- a/test/934-load-transform/build
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2016 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.
-
-./default-build "$@" --experimental agents
diff --git a/test/935-non-retransformable/build b/test/935-non-retransformable/build
deleted file mode 100755
index 898e2e5..0000000
--- a/test/935-non-retransformable/build
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2016 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.
-
-./default-build "$@" --experimental agents
diff --git a/test/936-search-onload/build b/test/936-search-onload/build
deleted file mode 100755
index 898e2e5..0000000
--- a/test/936-search-onload/build
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2016 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.
-
-./default-build "$@" --experimental agents
diff --git a/test/937-hello-retransform-package/build b/test/937-hello-retransform-package/build
deleted file mode 100755
index 898e2e5..0000000
--- a/test/937-hello-retransform-package/build
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2016 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.
-
-./default-build "$@" --experimental agents
diff --git a/test/938-load-transform-bcp/build b/test/938-load-transform-bcp/build
deleted file mode 100755
index 898e2e5..0000000
--- a/test/938-load-transform-bcp/build
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2016 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.
-
-./default-build "$@" --experimental agents
diff --git a/test/939-hello-transformation-bcp/build b/test/939-hello-transformation-bcp/build
deleted file mode 100755
index 898e2e5..0000000
--- a/test/939-hello-transformation-bcp/build
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2016 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.
-
-./default-build "$@" --experimental agents
diff --git a/test/940-recursive-obsolete/build b/test/940-recursive-obsolete/build
deleted file mode 100755
index 898e2e5..0000000
--- a/test/940-recursive-obsolete/build
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2016 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.
-
-./default-build "$@" --experimental agents
diff --git a/test/941-recurive-obsolete-jit/build b/test/941-recurive-obsolete-jit/build
deleted file mode 100755
index 898e2e5..0000000
--- a/test/941-recurive-obsolete-jit/build
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2016 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.
-
-./default-build "$@" --experimental agents
diff --git a/test/942-private-recursive/build b/test/942-private-recursive/build
deleted file mode 100755
index 898e2e5..0000000
--- a/test/942-private-recursive/build
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2016 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.
-
-./default-build "$@" --experimental agents
diff --git a/test/943-private-recursive-jit/build b/test/943-private-recursive-jit/build
deleted file mode 100755
index 898e2e5..0000000
--- a/test/943-private-recursive-jit/build
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2016 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.
-
-./default-build "$@" --experimental agents
diff --git a/test/944-transform-classloaders/build b/test/944-transform-classloaders/build
deleted file mode 100755
index 898e2e5..0000000
--- a/test/944-transform-classloaders/build
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2016 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.
-
-./default-build "$@" --experimental agents
diff --git a/test/945-obsolete-native/build b/test/945-obsolete-native/build
deleted file mode 100755
index 898e2e5..0000000
--- a/test/945-obsolete-native/build
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2016 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.
-
-./default-build "$@" --experimental agents
diff --git a/test/947-reflect-method/build b/test/947-reflect-method/build
deleted file mode 100755
index ebbc368..0000000
--- a/test/947-reflect-method/build
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# Copyright 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.
-
-./default-build "$@" --experimental agents
diff --git a/test/948-change-annotations/expected.txt b/test/948-change-annotations/expected.txt
index 680b18e..7974c7a 100644
--- a/test/948-change-annotations/expected.txt
+++ b/test/948-change-annotations/expected.txt
@@ -10,7 +10,7 @@
method public void Transform.sayHi() -> [@TestMethodAnnotation1(value=hi hi)]
hello
Goodbye
-Type annotations: [@TestClassAnnotation2(value=hello2), @TestClassAnnotation1(value=hello)]
+Type annotations: [@TestClassAnnotation1(value=hello), @TestClassAnnotation2(value=hello2)]
method public void Transform.sayHi() -> [@TestMethodAnnotation1(value=hi hi), @TestMethodAnnotation2(value=hi hi2)]
Running test class ChangeAnnotationValues
Type annotations: [@TestClassAnnotation1(value=hello)]
diff --git a/test/948-change-annotations/src/Main.java b/test/948-change-annotations/src/Main.java
index fe321e2..30bfbf9 100644
--- a/test/948-change-annotations/src/Main.java
+++ b/test/948-change-annotations/src/Main.java
@@ -16,6 +16,7 @@
import java.util.Arrays;
import java.util.Base64;
+import java.util.Comparator;
import java.lang.reflect.*;
import java.lang.annotation.*;
public class Main {
@@ -59,6 +60,11 @@
doTest(new ChangeAnnotationValues());
}
+ private static Annotation[] sortedAnno(Annotation[] annos) {
+ Arrays.sort(annos, Comparator.comparing((v) -> v.toString()));
+ return annos;
+ }
+
public static void doTest(TestCase t) {
// Get back to normal first.
doCommonClassRedefinition(Transform.class, INITIAL_CLASS_BYTES, INITIAL_DEX_BYTES);
@@ -69,9 +75,11 @@
}
private static void printAnnotations(Class<?> transform) {
- System.out.println("Type annotations: " + Arrays.toString(transform.getAnnotations()));
+ System.out.println("Type annotations: "
+ + Arrays.toString(sortedAnno(transform.getAnnotations())));
for (Method m : transform.getDeclaredMethods()) {
- System.out.println("method " + m + " -> " + Arrays.toString(m.getDeclaredAnnotations()));
+ System.out.println("method " + m + " -> "
+ + Arrays.toString(sortedAnno(m.getDeclaredAnnotations())));
}
}
diff --git a/test/949-in-memory-transform/expected.txt b/test/949-in-memory-transform/expected.txt
new file mode 100644
index 0000000..4774b81
--- /dev/null
+++ b/test/949-in-memory-transform/expected.txt
@@ -0,0 +1,2 @@
+hello
+Goodbye
diff --git a/test/949-in-memory-transform/info.txt b/test/949-in-memory-transform/info.txt
new file mode 100644
index 0000000..7753729
--- /dev/null
+++ b/test/949-in-memory-transform/info.txt
@@ -0,0 +1,4 @@
+Tests basic functions in the jvmti plugin.
+
+Tests that transformation works even when the class being transformed comes from
+an in-memory dex file (i.e. loaded from an InMemoryDexClassLoader).
diff --git a/test/946-obsolete-throw/build b/test/949-in-memory-transform/run
similarity index 92%
rename from test/946-obsolete-throw/build
rename to test/949-in-memory-transform/run
index ebbc368..e92b873 100755
--- a/test/946-obsolete-throw/build
+++ b/test/949-in-memory-transform/run
@@ -14,4 +14,4 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-./default-build "$@" --experimental agents
+./default-run "$@" --jvmti
diff --git a/test/949-in-memory-transform/src/Main.java b/test/949-in-memory-transform/src/Main.java
new file mode 100644
index 0000000..2ffabf5
--- /dev/null
+++ b/test/949-in-memory-transform/src/Main.java
@@ -0,0 +1,124 @@
+/*
+ * 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.
+ */
+
+import java.util.Base64;
+import java.lang.reflect.*;
+import java.nio.ByteBuffer;
+
+public class Main {
+ /**
+ * base64 encoded class/dex file for
+ * public class Transform {
+ * public void sayHi() {
+ * System.out.println("hello");
+ * }
+ * }
+ */
+ private static final byte[] INITIAL_CLASS_BYTES = Base64.getDecoder().decode(
+ "yv66vgAAADQAHAoABgAOCQAPABAIABEKABIAEwcAFAcAFQEABjxpbml0PgEAAygpVgEABENvZGUB" +
+ "AA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAA5UcmFuc2Zvcm0uamF2YQwA" +
+ "BwAIBwAWDAAXABgBAAVoZWxsbwcAGQwAGgAbAQAJVHJhbnNmb3JtAQAQamF2YS9sYW5nL09iamVj" +
+ "dAEAEGphdmEvbGFuZy9TeXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0cmVhbTsBABNqYXZh" +
+ "L2lvL1ByaW50U3RyZWFtAQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmluZzspVgAhAAUABgAA" +
+ "AAAAAgABAAcACAABAAkAAAAdAAEAAQAAAAUqtwABsQAAAAEACgAAAAYAAQAAABEAAQALAAgAAQAJ" +
+ "AAAAJQACAAEAAAAJsgACEgO2AASxAAAAAQAKAAAACgACAAAAGgAIABsAAQAMAAAAAgAN");
+ private static final byte[] INITIAL_DEX_BYTES = Base64.getDecoder().decode(
+ "ZGV4CjAzNQAJX3mZphwHJCT1qdTz/GS+jXOR+O/9e3fMAgAAcAAAAHhWNBIAAAAAAAAAACwCAAAO" +
+ "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAACsAQAAIAEAAGIB" +
+ "AABqAQAAdwEAAI4BAACiAQAAtgEAAMoBAADaAQAA3QEAAOEBAAD1AQAA/AEAAAECAAAKAgAAAQAA" +
+ "AAIAAAADAAAABAAAAAUAAAAHAAAABwAAAAUAAAAAAAAACAAAAAUAAABcAQAABAABAAsAAAAAAAAA" +
+ "AAAAAAAAAAANAAAAAQABAAwAAAACAAAAAAAAAAAAAAABAAAAAgAAAAAAAAAGAAAAAAAAABwCAAAA" +
+ "AAAAAQABAAEAAAARAgAABAAAAHAQAwAAAA4AAwABAAIAAAAWAgAACQAAAGIAAAAbAQoAAABuIAIA" +
+ "EAAOAAAAAQAAAAMABjxpbml0PgALTFRyYW5zZm9ybTsAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwAS" +
+ "TGphdmEvbGFuZy9PYmplY3Q7ABJMamF2YS9sYW5nL1N0cmluZzsAEkxqYXZhL2xhbmcvU3lzdGVt" +
+ "OwAOVHJhbnNmb3JtLmphdmEAAVYAAlZMABJlbWl0dGVyOiBqYWNrLTQuMjUABWhlbGxvAANvdXQA" +
+ "B3ByaW50bG4ABXNheUhpABEABw4AGgAHDocAAAABAQCBgASgAgEBuAIAAA0AAAAAAAAAAQAAAAAA" +
+ "AAABAAAADgAAAHAAAAACAAAABgAAAKgAAAADAAAAAgAAAMAAAAAEAAAAAQAAANgAAAAFAAAABAAA" +
+ "AOAAAAAGAAAAAQAAAAABAAABIAAAAgAAACABAAABEAAAAQAAAFwBAAACIAAADgAAAGIBAAADIAAA" +
+ "AgAAABECAAAAIAAAAQAAABwCAAAAEAAAAQAAACwCAAA=");
+
+
+ /**
+ * base64 encoded class/dex file for
+ * public class Transform {
+ * public void sayHi() {
+ * System.out.println("Goodbye");
+ * }
+ * }
+ */
+ private static final byte[] TRANSFORMED_CLASS_BYTES = Base64.getDecoder().decode(
+ "yv66vgAAADQAHAoABgAOCQAPABAIABEKABIAEwcAFAcAFQEABjxpbml0PgEAAygpVgEABENvZGUB" +
+ "AA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAA5UcmFuc2Zvcm0uamF2YQwA" +
+ "BwAIBwAWDAAXABgBAAdHb29kYnllBwAZDAAaABsBAAlUcmFuc2Zvcm0BABBqYXZhL2xhbmcvT2Jq" +
+ "ZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2ph" +
+ "dmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWACEABQAG" +
+ "AAAAAAACAAEABwAIAAEACQAAAB0AAQABAAAABSq3AAGxAAAAAQAKAAAABgABAAAAEQABAAsACAAB" +
+ "AAkAAAAlAAIAAQAAAAmyAAISA7YABLEAAAABAAoAAAAKAAIAAAAaAAgAGwABAAwAAAACAA0=");
+ private static final byte[] TRANSFORMED_DEX_BYTES = Base64.getDecoder().decode(
+ "ZGV4CjAzNQAPXh6T3l1FObhHsKf1U2vi+0GmAvElxBLMAgAAcAAAAHhWNBIAAAAAAAAAACwCAAAO" +
+ "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAACsAQAAIAEAAGIB" +
+ "AABqAQAAcwEAAIABAACXAQAAqwEAAL8BAADTAQAA4wEAAOYBAADqAQAA/gEAAAMCAAAMAgAAAgAA" +
+ "AAMAAAAEAAAABQAAAAYAAAAIAAAACAAAAAUAAAAAAAAACQAAAAUAAABcAQAABAABAAsAAAAAAAAA" +
+ "AAAAAAAAAAANAAAAAQABAAwAAAACAAAAAAAAAAAAAAABAAAAAgAAAAAAAAAHAAAAAAAAAB4CAAAA" +
+ "AAAAAQABAAEAAAATAgAABAAAAHAQAwAAAA4AAwABAAIAAAAYAgAACQAAAGIAAAAbAQEAAABuIAIA" +
+ "EAAOAAAAAQAAAAMABjxpbml0PgAHR29vZGJ5ZQALTFRyYW5zZm9ybTsAFUxqYXZhL2lvL1ByaW50" +
+ "U3RyZWFtOwASTGphdmEvbGFuZy9PYmplY3Q7ABJMamF2YS9sYW5nL1N0cmluZzsAEkxqYXZhL2xh" +
+ "bmcvU3lzdGVtOwAOVHJhbnNmb3JtLmphdmEAAVYAAlZMABJlbWl0dGVyOiBqYWNrLTQuMjUAA291" +
+ "dAAHcHJpbnRsbgAFc2F5SGkAEQAHDgAaAAcOhwAAAAEBAIGABKACAQG4Ag0AAAAAAAAAAQAAAAAA" +
+ "AAABAAAADgAAAHAAAAACAAAABgAAAKgAAAADAAAAAgAAAMAAAAAEAAAAAQAAANgAAAAFAAAABAAA" +
+ "AOAAAAAGAAAAAQAAAAABAAABIAAAAgAAACABAAABEAAAAQAAAFwBAAACIAAADgAAAGIBAAADIAAA" +
+ "AgAAABMCAAAAIAAAAQAAAB4CAAAAEAAAAQAAACwCAAA=");
+
+ public static void main(String[] args) throws Exception {
+ ClassLoader loader;
+ try {
+ // Art uses this classloader to do in-memory dex files. There is no support for defineClass
+ loader = (ClassLoader)Class.forName("dalvik.system.InMemoryDexClassLoader")
+ .getConstructor(ByteBuffer.class, ClassLoader.class)
+ .newInstance(ByteBuffer.wrap(INITIAL_DEX_BYTES),
+ ClassLoader.getSystemClassLoader());
+ } catch (ClassNotFoundException e) {
+ // Seem to be on RI. Just make a new ClassLoader that calls defineClass.
+ loader = new ClassLoader() {
+ public Class<?> findClass(String name) throws ClassNotFoundException {
+ if (name.equals("Transform")) {
+ return defineClass(name, INITIAL_CLASS_BYTES, 0, INITIAL_CLASS_BYTES.length);
+ } else {
+ throw new ClassNotFoundException("Couldn't find class: " + name);
+ }
+ }
+ };
+ }
+ doTest(loader);
+ }
+
+ public static void doTest(ClassLoader loader) throws Exception {
+ // Get the class
+ Class<?> transform_class = loader.loadClass("Transform");
+ Method say_hi_method = transform_class.getMethod("sayHi");
+ Object t = transform_class.newInstance();
+
+ // Run the actual test.
+ say_hi_method.invoke(t);
+ doCommonClassRedefinition(transform_class, TRANSFORMED_CLASS_BYTES, TRANSFORMED_DEX_BYTES);
+ say_hi_method.invoke(t);
+ }
+
+ // Transforms the class
+ private static native void doCommonClassRedefinition(Class<?> target,
+ byte[] class_file,
+ byte[] dex_file);
+}
diff --git a/test/956-methodhandles/src/Main.java b/test/956-methodhandles/src/Main.java
index fc9f030..cb06e42 100644
--- a/test/956-methodhandles/src/Main.java
+++ b/test/956-methodhandles/src/Main.java
@@ -183,15 +183,23 @@
public String bar();
}
- public static class BarSuper {
+ public static abstract class BarAbstractSuper {
+ public abstract String abstractSuperPublicMethod();
+ }
+
+ public static class BarSuper extends BarAbstractSuper {
public String superPublicMethod() {
return "superPublicMethod";
}
- public String superProtectedMethod() {
+ protected String superProtectedMethod() {
return "superProtectedMethod";
}
+ public String abstractSuperPublicMethod() {
+ return "abstractSuperPublicMethod";
+ }
+
String superPackageMethod() {
return "superPackageMethod";
}
@@ -288,15 +296,19 @@
System.out.println("Unexpected return value for BarImpl#bar: " + str);
}
- // TODO(narayan): Fix this case, we're using the wrong ArtMethod for the
- // invoke resulting in a failing check in the interpreter.
- //
- // mh = MethodHandles.lookup().findVirtual(Bar.class, "bar",
- // MethodType.methodType(String.class));
- // str = (String) mh.invoke(new BarImpl());
- // if (!"bar".equals(str)) {
- // System.out.println("Unexpected return value for BarImpl#bar: " + str);
- // }
+ mh = MethodHandles.lookup().findVirtual(Bar.class, "bar",
+ MethodType.methodType(String.class));
+ str = (String) mh.invoke(new BarImpl());
+ if (!"bar".equals(str)) {
+ System.out.println("Unexpected return value for BarImpl#bar: " + str);
+ }
+
+ mh = MethodHandles.lookup().findVirtual(BarAbstractSuper.class, "abstractSuperPublicMethod",
+ MethodType.methodType(String.class));
+ str = (String) mh.invoke(new BarImpl());
+ if (!"abstractSuperPublicMethod".equals(str)) {
+ System.out.println("Unexpected return value for BarImpl#abstractSuperPublicMethod: " + str);
+ }
// We should also be able to lookup public / protected / package methods in
// the super class, given sufficient access privileges.
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index 1938b92..c14a0b2 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -898,12 +898,24 @@
endif
endef
+COMPILER_TYPES_2 := optimizing
+COMPILER_TYPES_2 += interpreter
+COMPILER_TYPES_2 += jit
+COMPILER_TYPES_2 += regalloc_gc
+COMPILER_TYPES_2 += interp-ac
+ALL_ADDRESS_SIZES_2 := 32 64
+IMAGE_TYPES_2 := picimage
+IMAGE_TYPES_2 += no-image
+IMAGE_TYPES_2 += npicimage
+IMAGE_TYPES_2 += multinpicimage
+IMAGE_TYPES_2 += multipicimage
+
# Add core image dependencies required for given target - HOST or TARGET,
# IMAGE_TYPE, COMPILER_TYPE and ADDRESS_SIZE to the prereq_rules.
$(foreach target, $(TARGET_TYPES), \
- $(foreach image, $(IMAGE_TYPES), \
- $(foreach compiler, $(COMPILER_TYPES), \
- $(foreach address_size, $(ALL_ADDRESS_SIZES), $(eval \
+ $(foreach image, $(IMAGE_TYPES_2), \
+ $(foreach compiler, $(COMPILER_TYPES_2), \
+ $(foreach address_size, $(ALL_ADDRESS_SIZES_2), $(eval \
$(call core-image-dependencies,$(target),$(image),$(compiler),$(address_size)))))))
test-art-host-run-test-dependencies : $(host_prereq_rules)
diff --git a/test/etc/default-build b/test/etc/default-build
index 3d7b7dd..4318966 100755
--- a/test/etc/default-build
+++ b/test/etc/default-build
@@ -79,7 +79,7 @@
JACK_EXPERIMENTAL_ARGS["default-methods"]="-D jack.java.source.version=1.8 -D jack.android.min-api-level=24"
JACK_EXPERIMENTAL_ARGS["lambdas"]="-D jack.java.source.version=1.8 -D jack.android.min-api-level=24"
JACK_EXPERIMENTAL_ARGS["method-handles"]="-D jack.java.source.version=1.7 -D jack.android.min-api-level=o-b1"
-JACK_EXPERIMENTAL_ARGS["java-8"]="-D jack.java.source.version=1.8 -D jack.android.min-api-level=24"
+JACK_EXPERIMENTAL_ARGS[${DEFAULT_EXPERIMENT}]="-D jack.java.source.version=1.8 -D jack.android.min-api-level=24"
declare -A SMALI_EXPERIMENTAL_ARGS
SMALI_EXPERIMENTAL_ARGS["default-methods"]="--api-level 24"
@@ -90,6 +90,7 @@
JAVAC_EXPERIMENTAL_ARGS["default-methods"]="-source 1.8 -target 1.8"
JAVAC_EXPERIMENTAL_ARGS["lambdas"]="-source 1.8 -target 1.8"
JAVAC_EXPERIMENTAL_ARGS["method-handles"]="-source 1.8 -target 1.8"
+# We need to leave javac at default 1.7 so that dx will continue to work
JAVAC_EXPERIMENTAL_ARGS[${DEFAULT_EXPERIMENT}]="-source 1.7 -target 1.7"
JAVAC_EXPERIMENTAL_ARGS["agents"]="-source 1.8 -target 1.8"
diff --git a/test/run-test b/test/run-test
index c926c11..d55ba77 100755
--- a/test/run-test
+++ b/test/run-test
@@ -80,7 +80,7 @@
# ANDROID_HOST_OUT is not set in a build environment.
if [ -z "$ANDROID_HOST_OUT" ]; then
- export ANDROID_HOST_OUT=${OUT_DIR:-$ANDROID_BUILD_TOP/out/}host/linux-x86
+ export ANDROID_HOST_OUT=$ANDROID_BUILD_TOP/out/host/linux-x86
fi
# If JACK_CLASSPATH is not set, assume it only contains core-libart.
diff --git a/test/testrunner/testrunner.py b/test/testrunner/testrunner.py
index a5bfcff..5a6114e 100755
--- a/test/testrunner/testrunner.py
+++ b/test/testrunner/testrunner.py
@@ -446,29 +446,34 @@
test_name: The name of the test along with the variants.
"""
global stop_testrunner
- if is_test_disabled(test, test_variant):
- test_skipped = True
- else:
- test_skipped = False
- proc = subprocess.Popen(command.split(), stderr=subprocess.STDOUT, stdout=subprocess.PIPE)
- script_output = proc.stdout.read().strip()
- test_passed = not proc.wait()
-
- if not test_skipped:
- if test_passed:
- print_test_info(test_name, 'PASS')
+ try:
+ if is_test_disabled(test, test_variant):
+ test_skipped = True
else:
- failed_tests.append(test_name)
- if not env.ART_TEST_KEEP_GOING:
- stop_testrunner = True
- print_test_info(test_name, 'FAIL', ('%s\n%s') % (
- command, script_output))
- elif not dry_run:
- print_test_info(test_name, 'SKIP')
- skipped_tests.append(test_name)
- else:
- print_test_info(test_name, '')
- semaphore.release()
+ test_skipped = False
+ proc = subprocess.Popen(command.split(), stderr=subprocess.STDOUT, stdout=subprocess.PIPE)
+ script_output = proc.stdout.read().strip()
+ test_passed = not proc.wait()
+
+ if not test_skipped:
+ if test_passed:
+ print_test_info(test_name, 'PASS')
+ else:
+ failed_tests.append(test_name)
+ if not env.ART_TEST_KEEP_GOING:
+ stop_testrunner = True
+ print_test_info(test_name, 'FAIL', ('%s\n%s') % (
+ command, script_output))
+ elif not dry_run:
+ print_test_info(test_name, 'SKIP')
+ skipped_tests.append(test_name)
+ else:
+ print_test_info(test_name, '')
+ except Exception, e:
+ failed_tests.append(test_name)
+ print_text(('%s\n%s\n') % (command, str(e)))
+ finally:
+ semaphore.release()
def print_test_info(test_name, result, failed_test_info=""):
@@ -485,6 +490,7 @@
command used to invoke the script. It doesn't override the failing
test information in either of the cases.
"""
+
global test_count
info = ''
if not verbose:
@@ -493,48 +499,53 @@
# the console width.
console_width = int(os.popen('stty size', 'r').read().split()[1])
info = '\r' + ' ' * console_width + '\r'
- print_mutex.acquire()
- test_count += 1
- percent = (test_count * 100) / total_test_count
- progress_info = ('[ %d%% %d/%d ]') % (
- percent,
- test_count,
- total_test_count)
+ try:
+ print_mutex.acquire()
+ test_count += 1
+ percent = (test_count * 100) / total_test_count
+ progress_info = ('[ %d%% %d/%d ]') % (
+ percent,
+ test_count,
+ total_test_count)
- if result == "FAIL":
- info += ('%s %s %s\n%s\n') % (
- progress_info,
- test_name,
- COLOR_ERROR + 'FAIL' + COLOR_NORMAL,
- failed_test_info)
- else:
- result_text = ''
- if result == 'PASS':
- result_text += COLOR_PASS + 'PASS' + COLOR_NORMAL
- elif result == 'SKIP':
- result_text += COLOR_SKIP + 'SKIP' + COLOR_NORMAL
-
- if verbose:
- info += ('%s %s %s\n') % (
- progress_info,
- test_name,
- result_text)
- else:
- total_output_length = 2 # Two spaces
- total_output_length += len(progress_info)
- total_output_length += len(result)
- allowed_test_length = console_width - total_output_length
- test_name_len = len(test_name)
- if allowed_test_length < test_name_len:
- test_name = ('%s...%s') % (
- test_name[:(allowed_test_length - 3)/2],
- test_name[-(allowed_test_length - 3)/2:])
- info += ('%s %s %s') % (
+ if result == "FAIL":
+ info += ('%s %s %s\n%s\n') % (
progress_info,
test_name,
- result_text)
- print_text(info)
- print_mutex.release()
+ COLOR_ERROR + 'FAIL' + COLOR_NORMAL,
+ failed_test_info)
+ else:
+ result_text = ''
+ if result == 'PASS':
+ result_text += COLOR_PASS + 'PASS' + COLOR_NORMAL
+ elif result == 'SKIP':
+ result_text += COLOR_SKIP + 'SKIP' + COLOR_NORMAL
+
+ if verbose:
+ info += ('%s %s %s\n') % (
+ progress_info,
+ test_name,
+ result_text)
+ else:
+ total_output_length = 2 # Two spaces
+ total_output_length += len(progress_info)
+ total_output_length += len(result)
+ allowed_test_length = console_width - total_output_length
+ test_name_len = len(test_name)
+ if allowed_test_length < test_name_len:
+ test_name = ('%s...%s') % (
+ test_name[:(allowed_test_length - 3)/2],
+ test_name[-(allowed_test_length - 3)/2:])
+ info += ('%s %s %s') % (
+ progress_info,
+ test_name,
+ result_text)
+ print_text(info)
+ except Exception, e:
+ print_text(('%s\n%s\n') % (test_name, str(e)))
+ failed_tests.append(test_name)
+ finally:
+ print_mutex.release()
def get_disabled_test_info():
"""Generate set of known failures.
@@ -812,8 +823,10 @@
return test
def main():
+ global verbose
gather_test_info()
user_requested_test = parse_option()
+ verbose = True
setup_test_env()
if build:
build_targets = ''
@@ -837,15 +850,13 @@
while threading.active_count() > 1:
time.sleep(0.1)
print_analysis()
- if failed_tests:
- sys.exit(1)
- sys.exit(0)
- except SystemExit:
- pass
except Exception, e:
print_analysis()
print_text(str(e))
sys.exit(1)
+ if failed_tests:
+ sys.exit(1)
+ sys.exit(0)
if __name__ == '__main__':
main()
diff --git a/tools/libcore_failures.txt b/tools/libcore_failures.txt
index dcef8c0..08abdb3 100644
--- a/tools/libcore_failures.txt
+++ b/tools/libcore_failures.txt
@@ -105,12 +105,6 @@
names: ["org.apache.harmony.tests.java.lang.ProcessTest#test_getErrorStream"]
},
{
- description: "Short date format flag ignored for es_US locale.",
- result: EXEC_FAILED,
- name: "libcore.icu.DateIntervalFormatTest#test_formatDateInterval",
- bug: 18619426
-},
-{
description: "Error decoding digital signature bytes.",
result: EXEC_FAILED,
name: "org.apache.harmony.security.tests.java.security.Signature2Test#test_verify$BII",
@@ -134,12 +128,6 @@
names: ["org.apache.harmony.tests.java.lang.ProcessManagerTest#testEnvironment"]
},
{
- description: "Crypto failures",
- result: EXEC_FAILED,
- names: ["libcore.javax.crypto.CipherTest#testCipher_ShortBlock_Failure",
- "libcore.javax.crypto.CipherTest#testCipher_Success"]
-},
-{
description: "Flake when running with libartd.so or interpreter",
result: EXEC_FAILED,
bug:22106064,