summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build/Android.gtest.mk31
-rw-r--r--compiler/debug/elf_gnu_debugdata_writer.h13
-rw-r--r--compiler/optimizing/code_generator.cc40
-rw-r--r--compiler/optimizing/code_generator.h10
-rw-r--r--compiler/optimizing/code_generator_arm64.cc20
-rw-r--r--compiler/optimizing/code_generator_arm_vixl.cc20
-rw-r--r--compiler/optimizing/code_generator_mips.cc20
-rw-r--r--compiler/optimizing/code_generator_mips64.cc20
-rw-r--r--compiler/optimizing/code_generator_x86.cc20
-rw-r--r--compiler/optimizing/code_generator_x86_64.cc20
-rw-r--r--compiler/optimizing/graph_visualizer.cc12
-rw-r--r--compiler/optimizing/instruction_builder.cc28
-rw-r--r--compiler/optimizing/instruction_builder.h7
-rw-r--r--compiler/optimizing/nodes.h91
-rw-r--r--compiler/optimizing/reference_type_propagation.cc25
-rw-r--r--compiler/optimizing/reference_type_propagation.h4
-rw-r--r--compiler/utils/assembler_thumb_test_expected.cc.inc2
-rw-r--r--dex2oat/dex2oat.cc4
-rw-r--r--dex2oat/linker/oat_writer_test.cc2
-rw-r--r--dexlayout/Android.bp9
-rw-r--r--dexlayout/dexlayout.cc32
-rw-r--r--dexlayout/dexlayout_main.cc8
-rw-r--r--libdexfile/dex/dex_file_loader.cc2
-rw-r--r--libdexfile/dex/dex_file_loader.h2
-rw-r--r--libprofile/Android.bp1
-rw-r--r--profman/Android.bp4
-rw-r--r--profman/profman.cc67
-rw-r--r--runtime/Android.bp1
-rw-r--r--runtime/arch/arm/instruction_set_features_arm.cc2
-rw-r--r--runtime/arch/arm/quick_entrypoints_arm.S7
-rw-r--r--runtime/arch/arm64/instruction_set_features_arm64.cc2
-rw-r--r--runtime/arch/arm64/instruction_set_features_arm64_test.cc20
-rw-r--r--runtime/arch/arm64/quick_entrypoints_arm64.S7
-rw-r--r--runtime/arch/mips/entrypoints_init_mips.cc4
-rw-r--r--runtime/arch/mips/quick_entrypoints_mips.S19
-rw-r--r--runtime/arch/mips64/quick_entrypoints_mips64.S19
-rw-r--r--runtime/arch/x86/quick_entrypoints_x86.S9
-rw-r--r--runtime/arch/x86_64/quick_entrypoints_x86_64.S9
-rw-r--r--runtime/asm_support.h2
-rw-r--r--runtime/base/file_utils.cc15
-rw-r--r--runtime/class_loader_context.cc31
-rw-r--r--runtime/class_loader_context.h22
-rw-r--r--runtime/class_loader_context_test.cc44
-rw-r--r--runtime/dex/art_dex_file_loader.cc5
-rw-r--r--runtime/dex/art_dex_file_loader_test.cc61
-rw-r--r--runtime/entrypoints/entrypoint_utils.cc22
-rw-r--r--runtime/entrypoints/entrypoint_utils.h11
-rw-r--r--runtime/entrypoints/quick/quick_default_externs.h2
-rw-r--r--runtime/entrypoints/quick/quick_default_init_entrypoints.h2
-rw-r--r--runtime/entrypoints/quick/quick_dexcache_entrypoints.cc21
-rw-r--r--runtime/entrypoints/quick/quick_entrypoints_list.h2
-rw-r--r--runtime/entrypoints_order_test.cc4
-rw-r--r--runtime/jit/jit_code_cache.cc8
-rw-r--r--runtime/jit/jit_code_cache.h8
-rw-r--r--runtime/oat.h4
-rw-r--r--runtime/oat_file_assistant.cc4
-rw-r--r--runtime/oat_file_manager.cc96
-rw-r--r--runtime/oat_file_manager.h26
-rw-r--r--runtime/verifier/method_verifier.cc4
-rwxr-xr-xtest/172-app-image-twice/check18
-rw-r--r--test/172-app-image-twice/debug_print_class.cc33
-rw-r--r--test/172-app-image-twice/expected.txt1
-rw-r--r--test/172-app-image-twice/info.txt1
-rw-r--r--test/172-app-image-twice/profile1
-rw-r--r--test/172-app-image-twice/run28
-rw-r--r--test/172-app-image-twice/src/Main.java48
-rw-r--r--test/172-app-image-twice/src/TestClass.java18
-rw-r--r--test/979-const-method-handle/expected.txt3
-rw-r--r--test/979-const-method-handle/src/Main.java114
-rw-r--r--test/Android.bp1
-rw-r--r--test/knownfailures.json1
-rw-r--r--tools/veridex/flow_analysis.cc97
-rw-r--r--tools/veridex/flow_analysis.h23
-rw-r--r--tools/veridex/veridex.cc12
-rw-r--r--tools/veridex/veridex.h4
75 files changed, 1167 insertions, 243 deletions
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index be040a98da..3daaf0156e 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -483,18 +483,21 @@ maybe_chroot_command := chroot $(ART_TEST_CHROOT)
endif
# File witnessing the success of the gtest, the presence of which means the gtest's success.
-gtest_witness := $(maybe_art_test_chroot)$(ART_TARGET_TEST_DIR)/$(TARGET_$(3)ARCH)/$$@-$$$$PPID
+gtest_witness := \
+ $(maybe_art_test_chroot)$(ART_TARGET_TEST_DIR)/$(TARGET_$(3)ARCH)/$$(gtest_rule)-$$$$PPID
+
+$$(gtest_rule): GTEST_WITNESS := $$(gtest_witness)
.PHONY: $$(gtest_rule)
$$(gtest_rule): test-art-target-sync
- $(hide) adb shell touch $(gtest_witness)
- $(hide) adb shell rm $(gtest_witness)
+ $(hide) adb shell touch $$(GTEST_WITNESS)
+ $(hide) adb shell rm $$(GTEST_WITNESS)
$(hide) adb shell chmod 755 $(maybe_art_test_chroot)$$(PRIVATE_TARGET_EXE)
$(hide) $$(call ART_TEST_SKIP,$$@) && \
(adb shell "$(maybe_chroot_command) env $(GCOV_ENV) LD_LIBRARY_PATH=$(4) \
ANDROID_ROOT=$(ART_GTEST_TARGET_ANDROID_ROOT) $$(PRIVATE_TARGET_EXE) \
- && touch $(gtest_witness)" \
- && (adb pull $(gtest_witness) /tmp/ && $$(call ART_TEST_PASSED,$$@)) \
+ && touch $$(GTEST_WITNESS)" \
+ && (adb pull $$(GTEST_WITNESS) /tmp/ && $$(call ART_TEST_PASSED,$$@)) \
|| $$(call ART_TEST_FAILED,$$@))
$(hide) rm -f /tmp/$$@-$$$$PPID
@@ -502,20 +505,27 @@ $$(gtest_rule): test-art-target-sync
ART_TEST_TARGET_GTEST_RULES += $$(gtest_rule)
ART_TEST_TARGET_GTEST_$(1)_RULES += $$(gtest_rule)
+# File witnessing the success of the Valgrind gtest, the presence of which means the gtest's
+# success.
+valgrind_gtest_witness := \
+ $(maybe_art_test_chroot)$(ART_TARGET_TEST_DIR)/$(TARGET_$(3)ARCH)/valgrind-$$(gtest_rule)-$$$$PPID
+
+valgrind-$$(gtest_rule): VALGRIND_GTEST_WITNESS := $$(valgrind_gtest_witness)
+
.PHONY: valgrind-$$(gtest_rule)
valgrind-$$(gtest_rule): $(ART_VALGRIND_TARGET_DEPENDENCIES) test-art-target-sync
- $(hide) adb shell touch $(gtest_witness)
- $(hide) adb shell rm $(gtest_witness)
+ $(hide) adb shell touch $$(VALGRIND_GTEST_WITNESS)
+ $(hide) adb shell rm $$(VALGRIND_GTEST_WITNESS)
$(hide) adb shell chmod 755 $(maybe_art_test_chroot)$$(PRIVATE_TARGET_EXE)
$(hide) $$(call ART_TEST_SKIP,$$@) && \
(adb shell "$(maybe_chroot_command) env $(GCOV_ENV) LD_LIBRARY_PATH=$(4) \
ANDROID_ROOT=$(ART_GTEST_TARGET_ANDROID_ROOT) \
- $$$$ANDROID_ROOT/bin/valgrind \
+ $(ART_GTEST_TARGET_ANDROID_ROOT)/bin/valgrind \
--leak-check=full --error-exitcode=1 --workaround-gcc296-bugs=yes \
--suppressions=$(ART_TARGET_TEST_DIR)/valgrind-target-suppressions.txt \
--num-callers=50 --show-mismatched-frees=no $$(PRIVATE_TARGET_EXE) \
- && touch $(gtest_witness)" \
- && (adb pull $(gtest_witness) /tmp/ && $$(call ART_TEST_PASSED,$$@)) \
+ && touch $$(VALGRIND_GTEST_WITNESS)" \
+ && (adb pull $$(VALGRIND_GTEST_WITNESS) /tmp/ && $$(call ART_TEST_PASSED,$$@)) \
|| $$(call ART_TEST_FAILED,$$@))
$(hide) rm -f /tmp/$$@-$$$$PPID
@@ -525,6 +535,7 @@ valgrind-$$(gtest_rule): $(ART_VALGRIND_TARGET_DEPENDENCIES) test-art-target-syn
ART_TEST_TARGET_VALGRIND_GTEST_$(1)_RULES += valgrind-$$(gtest_rule)
# Clear locally defined variables.
+ valgrind_gtest_witness :=
gtest_witness :=
maybe_chroot_command :=
maybe_art_test_chroot :=
diff --git a/compiler/debug/elf_gnu_debugdata_writer.h b/compiler/debug/elf_gnu_debugdata_writer.h
index a88c5cb213..fd132f4ac4 100644
--- a/compiler/debug/elf_gnu_debugdata_writer.h
+++ b/compiler/debug/elf_gnu_debugdata_writer.h
@@ -41,23 +41,23 @@ static void XzCompress(const std::vector<uint8_t>* src, std::vector<uint8_t>* ds
Lzma2EncProps_Normalize(&lzma2Props);
CXzProps props;
XzProps_Init(&props);
- props.lzma2Props = &lzma2Props;
+ props.lzma2Props = lzma2Props;
// Implement the required interface for communication (written in C so no virtual methods).
struct XzCallbacks : public ISeqInStream, public ISeqOutStream, public ICompressProgress {
- static SRes ReadImpl(void* p, void* buf, size_t* size) {
- auto* ctx = static_cast<XzCallbacks*>(reinterpret_cast<ISeqInStream*>(p));
+ static SRes ReadImpl(const ISeqInStream* p, void* buf, size_t* size) {
+ auto* ctx = static_cast<XzCallbacks*>(const_cast<ISeqInStream*>(p));
*size = std::min(*size, ctx->src_->size() - ctx->src_pos_);
memcpy(buf, ctx->src_->data() + ctx->src_pos_, *size);
ctx->src_pos_ += *size;
return SZ_OK;
}
- static size_t WriteImpl(void* p, const void* buf, size_t size) {
- auto* ctx = static_cast<XzCallbacks*>(reinterpret_cast<ISeqOutStream*>(p));
+ static size_t WriteImpl(const ISeqOutStream* p, const void* buf, size_t size) {
+ auto* ctx = static_cast<const XzCallbacks*>(p);
const uint8_t* buffer = reinterpret_cast<const uint8_t*>(buf);
ctx->dst_->insert(ctx->dst_->end(), buffer, buffer + size);
return size;
}
- static SRes ProgressImpl(void* , UInt64, UInt64) {
+ static SRes ProgressImpl(const ICompressProgress* , UInt64, UInt64) {
return SZ_OK;
}
size_t src_pos_;
@@ -113,4 +113,3 @@ static std::vector<uint8_t> MakeMiniDebugInfoInternal(
} // namespace art
#endif // ART_COMPILER_DEBUG_ELF_GNU_DEBUGDATA_WRITER_H_
-
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index 231017f55e..f57333741c 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -736,6 +736,46 @@ void CodeGenerator::GenerateLoadClassRuntimeCall(HLoadClass* cls) {
}
}
+void CodeGenerator::CreateLoadMethodHandleRuntimeCallLocationSummary(
+ HLoadMethodHandle* method_handle,
+ Location runtime_proto_index_location,
+ Location runtime_return_location) {
+ DCHECK_EQ(method_handle->InputCount(), 1u);
+ LocationSummary* locations =
+ new (method_handle->GetBlock()->GetGraph()->GetAllocator()) LocationSummary(
+ method_handle, LocationSummary::kCallOnMainOnly);
+ locations->SetInAt(0, Location::NoLocation());
+ locations->AddTemp(runtime_proto_index_location);
+ locations->SetOut(runtime_return_location);
+}
+
+void CodeGenerator::GenerateLoadMethodHandleRuntimeCall(HLoadMethodHandle* method_handle) {
+ LocationSummary* locations = method_handle->GetLocations();
+ MoveConstant(locations->GetTemp(0), method_handle->GetMethodHandleIndex());
+ CheckEntrypointTypes<kQuickResolveMethodHandle, void*, uint32_t>();
+ InvokeRuntime(kQuickResolveMethodHandle, method_handle, method_handle->GetDexPc());
+}
+
+void CodeGenerator::CreateLoadMethodTypeRuntimeCallLocationSummary(
+ HLoadMethodType* method_type,
+ Location runtime_proto_index_location,
+ Location runtime_return_location) {
+ DCHECK_EQ(method_type->InputCount(), 1u);
+ LocationSummary* locations =
+ new (method_type->GetBlock()->GetGraph()->GetAllocator()) LocationSummary(
+ method_type, LocationSummary::kCallOnMainOnly);
+ locations->SetInAt(0, Location::NoLocation());
+ locations->AddTemp(runtime_proto_index_location);
+ locations->SetOut(runtime_return_location);
+}
+
+void CodeGenerator::GenerateLoadMethodTypeRuntimeCall(HLoadMethodType* method_type) {
+ LocationSummary* locations = method_type->GetLocations();
+ MoveConstant(locations->GetTemp(0), method_type->GetProtoIndex());
+ CheckEntrypointTypes<kQuickResolveMethodType, void*, uint32_t>();
+ InvokeRuntime(kQuickResolveMethodType, method_type, method_type->GetDexPc());
+}
+
static uint32_t GetBootImageOffsetImpl(const void* object, ImageHeader::ImageSections section) {
Runtime* runtime = Runtime::Current();
DCHECK(runtime->IsAotCompiler());
diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h
index f0c4ee01cc..bcb25997f4 100644
--- a/compiler/optimizing/code_generator.h
+++ b/compiler/optimizing/code_generator.h
@@ -564,6 +564,16 @@ class CodeGenerator : public DeletableArenaObject<kArenaAllocCodeGenerator> {
Location runtime_return_location);
void GenerateLoadClassRuntimeCall(HLoadClass* cls);
+ static void CreateLoadMethodHandleRuntimeCallLocationSummary(HLoadMethodHandle* method_handle,
+ Location runtime_handle_index_location,
+ Location runtime_return_location);
+ void GenerateLoadMethodHandleRuntimeCall(HLoadMethodHandle* method_handle);
+
+ static void CreateLoadMethodTypeRuntimeCallLocationSummary(HLoadMethodType* method_type,
+ Location runtime_type_index_location,
+ Location runtime_return_location);
+ void GenerateLoadMethodTypeRuntimeCall(HLoadMethodType* method_type);
+
uint32_t GetBootImageOffset(HLoadClass* load_class);
uint32_t GetBootImageOffset(HLoadString* load_string);
uint32_t GetBootImageOffset(HInvokeStaticOrDirect* invoke);
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index d4cfab82de..6f173e19f5 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -5144,6 +5144,26 @@ void InstructionCodeGeneratorARM64::VisitLoadClass(HLoadClass* cls) NO_THREAD_SA
}
}
+void LocationsBuilderARM64::VisitLoadMethodHandle(HLoadMethodHandle* load) {
+ InvokeRuntimeCallingConvention calling_convention;
+ Location location = LocationFrom(calling_convention.GetRegisterAt(0));
+ CodeGenerator::CreateLoadMethodHandleRuntimeCallLocationSummary(load, location, location);
+}
+
+void InstructionCodeGeneratorARM64::VisitLoadMethodHandle(HLoadMethodHandle* load) {
+ codegen_->GenerateLoadMethodHandleRuntimeCall(load);
+}
+
+void LocationsBuilderARM64::VisitLoadMethodType(HLoadMethodType* load) {
+ InvokeRuntimeCallingConvention calling_convention;
+ Location location = LocationFrom(calling_convention.GetRegisterAt(0));
+ CodeGenerator::CreateLoadMethodTypeRuntimeCallLocationSummary(load, location, location);
+}
+
+void InstructionCodeGeneratorARM64::VisitLoadMethodType(HLoadMethodType* load) {
+ codegen_->GenerateLoadMethodTypeRuntimeCall(load);
+}
+
static MemOperand GetExceptionTlsAddress() {
return MemOperand(tr, Thread::ExceptionOffset<kArm64PointerSize>().Int32Value());
}
diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc
index 58ce9aa9f0..859e1597c6 100644
--- a/compiler/optimizing/code_generator_arm_vixl.cc
+++ b/compiler/optimizing/code_generator_arm_vixl.cc
@@ -7527,6 +7527,26 @@ void InstructionCodeGeneratorARMVIXL::VisitLoadClass(HLoadClass* cls) NO_THREAD_
}
}
+void LocationsBuilderARMVIXL::VisitLoadMethodHandle(HLoadMethodHandle* load) {
+ InvokeRuntimeCallingConventionARMVIXL calling_convention;
+ Location location = LocationFrom(calling_convention.GetRegisterAt(0));
+ CodeGenerator::CreateLoadMethodHandleRuntimeCallLocationSummary(load, location, location);
+}
+
+void InstructionCodeGeneratorARMVIXL::VisitLoadMethodHandle(HLoadMethodHandle* load) {
+ codegen_->GenerateLoadMethodHandleRuntimeCall(load);
+}
+
+void LocationsBuilderARMVIXL::VisitLoadMethodType(HLoadMethodType* load) {
+ InvokeRuntimeCallingConventionARMVIXL calling_convention;
+ Location location = LocationFrom(calling_convention.GetRegisterAt(0));
+ CodeGenerator::CreateLoadMethodTypeRuntimeCallLocationSummary(load, location, location);
+}
+
+void InstructionCodeGeneratorARMVIXL::VisitLoadMethodType(HLoadMethodType* load) {
+ codegen_->GenerateLoadMethodTypeRuntimeCall(load);
+}
+
void LocationsBuilderARMVIXL::VisitClinitCheck(HClinitCheck* check) {
LocationSummary* locations =
new (GetGraph()->GetAllocator()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc
index 25e2eddbfa..7f3441fdf4 100644
--- a/compiler/optimizing/code_generator_mips.cc
+++ b/compiler/optimizing/code_generator_mips.cc
@@ -8226,6 +8226,26 @@ void InstructionCodeGeneratorMIPS::VisitLoadClass(HLoadClass* cls) NO_THREAD_SAF
}
}
+void LocationsBuilderMIPS::VisitLoadMethodHandle(HLoadMethodHandle* load) {
+ InvokeRuntimeCallingConvention calling_convention;
+ Location loc = Location::RegisterLocation(calling_convention.GetRegisterAt(0));
+ CodeGenerator::CreateLoadMethodHandleRuntimeCallLocationSummary(load, loc, loc);
+}
+
+void InstructionCodeGeneratorMIPS::VisitLoadMethodHandle(HLoadMethodHandle* load) {
+ codegen_->GenerateLoadMethodHandleRuntimeCall(load);
+}
+
+void LocationsBuilderMIPS::VisitLoadMethodType(HLoadMethodType* load) {
+ InvokeRuntimeCallingConvention calling_convention;
+ Location loc = Location::RegisterLocation(calling_convention.GetRegisterAt(0));
+ CodeGenerator::CreateLoadMethodTypeRuntimeCallLocationSummary(load, loc, loc);
+}
+
+void InstructionCodeGeneratorMIPS::VisitLoadMethodType(HLoadMethodType* load) {
+ codegen_->GenerateLoadMethodTypeRuntimeCall(load);
+}
+
static int32_t GetExceptionTlsOffset() {
return Thread::ExceptionOffset<kMipsPointerSize>().Int32Value();
}
diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc
index 5b07b55cbb..ee32b96daf 100644
--- a/compiler/optimizing/code_generator_mips64.cc
+++ b/compiler/optimizing/code_generator_mips64.cc
@@ -6262,6 +6262,26 @@ void InstructionCodeGeneratorMIPS64::VisitLoadClass(HLoadClass* cls) NO_THREAD_S
}
}
+void LocationsBuilderMIPS64::VisitLoadMethodHandle(HLoadMethodHandle* load) {
+ InvokeRuntimeCallingConvention calling_convention;
+ Location loc = Location::RegisterLocation(calling_convention.GetRegisterAt(0));
+ CodeGenerator::CreateLoadMethodHandleRuntimeCallLocationSummary(load, loc, loc);
+}
+
+void InstructionCodeGeneratorMIPS64::VisitLoadMethodHandle(HLoadMethodHandle* load) {
+ codegen_->GenerateLoadMethodHandleRuntimeCall(load);
+}
+
+void LocationsBuilderMIPS64::VisitLoadMethodType(HLoadMethodType* load) {
+ InvokeRuntimeCallingConvention calling_convention;
+ Location loc = Location::RegisterLocation(calling_convention.GetRegisterAt(0));
+ CodeGenerator::CreateLoadMethodTypeRuntimeCallLocationSummary(load, loc, loc);
+}
+
+void InstructionCodeGeneratorMIPS64::VisitLoadMethodType(HLoadMethodType* load) {
+ codegen_->GenerateLoadMethodTypeRuntimeCall(load);
+}
+
static int32_t GetExceptionTlsOffset() {
return Thread::ExceptionOffset<kMips64PointerSize>().Int32Value();
}
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 82d1fda878..9e315381b1 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -6539,6 +6539,26 @@ void InstructionCodeGeneratorX86::VisitLoadClass(HLoadClass* cls) NO_THREAD_SAFE
}
}
+void LocationsBuilderX86::VisitLoadMethodHandle(HLoadMethodHandle* load) {
+ InvokeRuntimeCallingConvention calling_convention;
+ Location location = Location::RegisterLocation(calling_convention.GetRegisterAt(0));
+ CodeGenerator::CreateLoadMethodHandleRuntimeCallLocationSummary(load, location, location);
+}
+
+void InstructionCodeGeneratorX86::VisitLoadMethodHandle(HLoadMethodHandle* load) {
+ codegen_->GenerateLoadMethodHandleRuntimeCall(load);
+}
+
+void LocationsBuilderX86::VisitLoadMethodType(HLoadMethodType* load) {
+ InvokeRuntimeCallingConvention calling_convention;
+ Location location = Location::RegisterLocation(calling_convention.GetRegisterAt(0));
+ CodeGenerator::CreateLoadMethodTypeRuntimeCallLocationSummary(load, location, location);
+}
+
+void InstructionCodeGeneratorX86::VisitLoadMethodType(HLoadMethodType* load) {
+ codegen_->GenerateLoadMethodTypeRuntimeCall(load);
+}
+
void LocationsBuilderX86::VisitClinitCheck(HClinitCheck* check) {
LocationSummary* locations =
new (GetGraph()->GetAllocator()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index 322b0cfc4c..f7397046d7 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -5908,6 +5908,26 @@ void LocationsBuilderX86_64::VisitClinitCheck(HClinitCheck* check) {
}
}
+void LocationsBuilderX86_64::VisitLoadMethodHandle(HLoadMethodHandle* load) {
+ // Custom calling convention: RAX serves as both input and output.
+ Location location = Location::RegisterLocation(RAX);
+ CodeGenerator::CreateLoadMethodHandleRuntimeCallLocationSummary(load, location, location);
+}
+
+void InstructionCodeGeneratorX86_64::VisitLoadMethodHandle(HLoadMethodHandle* load) {
+ codegen_->GenerateLoadMethodHandleRuntimeCall(load);
+}
+
+void LocationsBuilderX86_64::VisitLoadMethodType(HLoadMethodType* load) {
+ // Custom calling convention: RAX serves as both input and output.
+ Location location = Location::RegisterLocation(RAX);
+ CodeGenerator::CreateLoadMethodTypeRuntimeCallLocationSummary(load, location, location);
+}
+
+void InstructionCodeGeneratorX86_64::VisitLoadMethodType(HLoadMethodType* load) {
+ codegen_->GenerateLoadMethodTypeRuntimeCall(load);
+}
+
void InstructionCodeGeneratorX86_64::VisitClinitCheck(HClinitCheck* check) {
// We assume the class to not be null.
SlowPathCode* slow_path = new (codegen_->GetScopedAllocator()) LoadClassSlowPathX86_64(
diff --git a/compiler/optimizing/graph_visualizer.cc b/compiler/optimizing/graph_visualizer.cc
index 54d4644580..d65ad40565 100644
--- a/compiler/optimizing/graph_visualizer.cc
+++ b/compiler/optimizing/graph_visualizer.cc
@@ -386,6 +386,18 @@ class HGraphVisualizerPrinter : public HGraphDelegateVisitor {
<< load_class->NeedsAccessCheck() << std::noboolalpha;
}
+ void VisitLoadMethodHandle(HLoadMethodHandle* load_method_handle) OVERRIDE {
+ StartAttributeStream("load_kind") << "RuntimeCall";
+ StartAttributeStream("method_handle_index") << load_method_handle->GetMethodHandleIndex();
+ }
+
+ void VisitLoadMethodType(HLoadMethodType* load_method_type) OVERRIDE {
+ StartAttributeStream("load_kind") << "RuntimeCall";
+ const DexFile& dex_file = load_method_type->GetDexFile();
+ const DexFile::ProtoId& proto_id = dex_file.GetProtoId(load_method_type->GetProtoIndex());
+ StartAttributeStream("method_type") << dex_file.GetProtoSignature(proto_id);
+ }
+
void VisitLoadString(HLoadString* load_string) OVERRIDE {
StartAttributeStream("load_kind") << load_string->GetLoadKind();
}
diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc
index 9647dd5d41..35a39456a2 100644
--- a/compiler/optimizing/instruction_builder.cc
+++ b/compiler/optimizing/instruction_builder.cc
@@ -1896,6 +1896,20 @@ bool HInstructionBuilder::LoadClassNeedsAccessCheck(Handle<mirror::Class> klass)
}
}
+void HInstructionBuilder::BuildLoadMethodHandle(uint16_t proto_idx, uint32_t dex_pc) {
+ const DexFile& dex_file = *dex_compilation_unit_->GetDexFile();
+ HLoadMethodHandle* load_method_handle =
+ new (allocator_) HLoadMethodHandle(graph_->GetCurrentMethod(), proto_idx, dex_file, dex_pc);
+ AppendInstruction(load_method_handle);
+}
+
+void HInstructionBuilder::BuildLoadMethodType(uint16_t proto_idx, uint32_t dex_pc) {
+ const DexFile& dex_file = *dex_compilation_unit_->GetDexFile();
+ HLoadMethodType* load_method_type =
+ new (allocator_) HLoadMethodType(graph_->GetCurrentMethod(), proto_idx, dex_file, dex_pc);
+ AppendInstruction(load_method_type);
+}
+
void HInstructionBuilder::BuildTypeCheck(const Instruction& instruction,
uint8_t destination,
uint8_t reference,
@@ -2927,6 +2941,20 @@ bool HInstructionBuilder::ProcessDexInstruction(const Instruction& instruction,
break;
}
+ case Instruction::CONST_METHOD_HANDLE: {
+ uint16_t method_handle_idx = instruction.VRegB_21c();
+ BuildLoadMethodHandle(method_handle_idx, dex_pc);
+ UpdateLocal(instruction.VRegA_21c(), current_block_->GetLastInstruction());
+ break;
+ }
+
+ case Instruction::CONST_METHOD_TYPE: {
+ uint16_t proto_idx = instruction.VRegB_21c();
+ BuildLoadMethodType(proto_idx, dex_pc);
+ UpdateLocal(instruction.VRegA_21c(), current_block_->GetLastInstruction());
+ break;
+ }
+
case Instruction::MOVE_EXCEPTION: {
AppendInstruction(new (allocator_) HLoadException(dex_pc));
UpdateLocal(instruction.VRegA_11x(), current_block_->GetLastInstruction());
diff --git a/compiler/optimizing/instruction_builder.h b/compiler/optimizing/instruction_builder.h
index f78829232d..95ffa6b054 100644
--- a/compiler/optimizing/instruction_builder.h
+++ b/compiler/optimizing/instruction_builder.h
@@ -45,6 +45,7 @@ class VariableSizedHandleScope;
namespace mirror {
class Class;
+class MethodType;
} // namespace mirror
class HInstructionBuilder : public ValueObject {
@@ -239,6 +240,12 @@ class HInstructionBuilder : public ValueObject {
bool LoadClassNeedsAccessCheck(Handle<mirror::Class> klass)
REQUIRES_SHARED(Locks::mutator_lock_);
+ // Builds a `HLoadMethodHandle` loading the given `method_handle_idx`.
+ void BuildLoadMethodHandle(uint16_t method_handle_idx, uint32_t dex_pc);
+
+ // Builds a `HLoadMethodType` loading the given `proto_idx`.
+ void BuildLoadMethodType(uint16_t proto_idx, uint32_t dex_pc);
+
// Returns the outer-most compiling method's class.
ObjPtr<mirror::Class> GetOutermostCompilingClass() const;
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 9dcd741388..a7c2d0b125 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -41,6 +41,7 @@
#include "intrinsics_enum.h"
#include "locations.h"
#include "mirror/class.h"
+#include "mirror/method_type.h"
#include "offsets.h"
#include "utils/intrusive_forward_list.h"
@@ -1382,6 +1383,8 @@ class HLoopInformationOutwardIterator : public ValueObject {
M(LessThanOrEqual, Condition) \
M(LoadClass, Instruction) \
M(LoadException, Instruction) \
+ M(LoadMethodHandle, Instruction) \
+ M(LoadMethodType, Instruction) \
M(LoadString, Instruction) \
M(LongConstant, Constant) \
M(Max, Instruction) \
@@ -6498,6 +6501,94 @@ inline void HLoadString::AddSpecialInput(HInstruction* special_input) {
special_input->AddUseAt(this, 0);
}
+class HLoadMethodHandle FINAL : public HInstruction {
+ public:
+ HLoadMethodHandle(HCurrentMethod* current_method,
+ uint16_t method_handle_idx,
+ const DexFile& dex_file,
+ uint32_t dex_pc)
+ : HInstruction(kLoadMethodHandle,
+ DataType::Type::kReference,
+ SideEffectsForArchRuntimeCalls(),
+ dex_pc),
+ special_input_(HUserRecord<HInstruction*>(current_method)),
+ method_handle_idx_(method_handle_idx),
+ dex_file_(dex_file) {
+ }
+
+ using HInstruction::GetInputRecords; // Keep the const version visible.
+ ArrayRef<HUserRecord<HInstruction*>> GetInputRecords() OVERRIDE FINAL {
+ return ArrayRef<HUserRecord<HInstruction*>>(
+ &special_input_, (special_input_.GetInstruction() != nullptr) ? 1u : 0u);
+ }
+
+ bool IsClonable() const OVERRIDE { return true; }
+
+ uint16_t GetMethodHandleIndex() const { return method_handle_idx_; }
+
+ const DexFile& GetDexFile() const { return dex_file_; }
+
+ static SideEffects SideEffectsForArchRuntimeCalls() {
+ return SideEffects::CanTriggerGC();
+ }
+
+ DECLARE_INSTRUCTION(LoadMethodHandle);
+
+ protected:
+ DEFAULT_COPY_CONSTRUCTOR(LoadMethodHandle);
+
+ private:
+ // The special input is the HCurrentMethod for kRuntimeCall.
+ HUserRecord<HInstruction*> special_input_;
+
+ const uint16_t method_handle_idx_;
+ const DexFile& dex_file_;
+};
+
+class HLoadMethodType FINAL : public HInstruction {
+ public:
+ HLoadMethodType(HCurrentMethod* current_method,
+ uint16_t proto_idx,
+ const DexFile& dex_file,
+ uint32_t dex_pc)
+ : HInstruction(kLoadMethodType,
+ DataType::Type::kReference,
+ SideEffectsForArchRuntimeCalls(),
+ dex_pc),
+ special_input_(HUserRecord<HInstruction*>(current_method)),
+ proto_idx_(proto_idx),
+ dex_file_(dex_file) {
+ }
+
+ using HInstruction::GetInputRecords; // Keep the const version visible.
+ ArrayRef<HUserRecord<HInstruction*>> GetInputRecords() OVERRIDE FINAL {
+ return ArrayRef<HUserRecord<HInstruction*>>(
+ &special_input_, (special_input_.GetInstruction() != nullptr) ? 1u : 0u);
+ }
+
+ bool IsClonable() const OVERRIDE { return true; }
+
+ uint16_t GetProtoIndex() const { return proto_idx_; }
+
+ const DexFile& GetDexFile() const { return dex_file_; }
+
+ static SideEffects SideEffectsForArchRuntimeCalls() {
+ return SideEffects::CanTriggerGC();
+ }
+
+ DECLARE_INSTRUCTION(LoadMethodType);
+
+ protected:
+ DEFAULT_COPY_CONSTRUCTOR(LoadMethodType);
+
+ private:
+ // The special input is the HCurrentMethod for kRuntimeCall.
+ HUserRecord<HInstruction*> special_input_;
+
+ const uint16_t proto_idx_;
+ const DexFile& dex_file_;
+};
+
/**
* Performs an initialization check on its Class object input.
*/
diff --git a/compiler/optimizing/reference_type_propagation.cc b/compiler/optimizing/reference_type_propagation.cc
index c47c69af67..ecfa790b91 100644
--- a/compiler/optimizing/reference_type_propagation.cc
+++ b/compiler/optimizing/reference_type_propagation.cc
@@ -59,6 +59,18 @@ ReferenceTypeInfo::TypeHandle ReferenceTypePropagation::HandleCache::GetClassCla
return GetRootHandle(handles_, ClassLinker::kJavaLangClass, &class_class_handle_);
}
+ReferenceTypeInfo::TypeHandle ReferenceTypePropagation::HandleCache::GetMethodHandleClassHandle() {
+ return GetRootHandle(handles_,
+ ClassLinker::kJavaLangInvokeMethodHandleImpl,
+ &method_handle_class_handle_);
+}
+
+ReferenceTypeInfo::TypeHandle ReferenceTypePropagation::HandleCache::GetMethodTypeClassHandle() {
+ return GetRootHandle(handles_,
+ ClassLinker::kJavaLangInvokeMethodType,
+ &method_type_class_handle_);
+}
+
ReferenceTypeInfo::TypeHandle ReferenceTypePropagation::HandleCache::GetStringClassHandle() {
return GetRootHandle(handles_, ClassLinker::kJavaLangString, &string_class_handle_);
}
@@ -89,6 +101,8 @@ class ReferenceTypePropagation::RTPVisitor : public HGraphDelegateVisitor {
void VisitLoadClass(HLoadClass* load_class) OVERRIDE;
void VisitInstanceOf(HInstanceOf* load_class) OVERRIDE;
void VisitClinitCheck(HClinitCheck* clinit_check) OVERRIDE;
+ void VisitLoadMethodHandle(HLoadMethodHandle* instr) OVERRIDE;
+ void VisitLoadMethodType(HLoadMethodType* instr) OVERRIDE;
void VisitLoadString(HLoadString* instr) OVERRIDE;
void VisitLoadException(HLoadException* instr) OVERRIDE;
void VisitNewArray(HNewArray* instr) OVERRIDE;
@@ -668,6 +682,17 @@ void ReferenceTypePropagation::RTPVisitor::VisitClinitCheck(HClinitCheck* instr)
instr->SetReferenceTypeInfo(instr->InputAt(0)->GetReferenceTypeInfo());
}
+void ReferenceTypePropagation::RTPVisitor::VisitLoadMethodHandle(HLoadMethodHandle* instr) {
+ instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(
+ handle_cache_->GetMethodHandleClassHandle(),
+ /* is_exact */ true));
+}
+
+void ReferenceTypePropagation::RTPVisitor::VisitLoadMethodType(HLoadMethodType* instr) {
+ instr->SetReferenceTypeInfo(
+ ReferenceTypeInfo::Create(handle_cache_->GetMethodTypeClassHandle(), /* is_exact */ true));
+}
+
void ReferenceTypePropagation::RTPVisitor::VisitLoadString(HLoadString* instr) {
instr->SetReferenceTypeInfo(
ReferenceTypeInfo::Create(handle_cache_->GetStringClassHandle(), /* is_exact */ true));
diff --git a/compiler/optimizing/reference_type_propagation.h b/compiler/optimizing/reference_type_propagation.h
index 400852f4dc..d36d592708 100644
--- a/compiler/optimizing/reference_type_propagation.h
+++ b/compiler/optimizing/reference_type_propagation.h
@@ -75,6 +75,8 @@ class ReferenceTypePropagation : public HOptimization {
ReferenceTypeInfo::TypeHandle GetObjectClassHandle();
ReferenceTypeInfo::TypeHandle GetClassClassHandle();
+ ReferenceTypeInfo::TypeHandle GetMethodHandleClassHandle();
+ ReferenceTypeInfo::TypeHandle GetMethodTypeClassHandle();
ReferenceTypeInfo::TypeHandle GetStringClassHandle();
ReferenceTypeInfo::TypeHandle GetThrowableClassHandle();
@@ -83,6 +85,8 @@ class ReferenceTypePropagation : public HOptimization {
ReferenceTypeInfo::TypeHandle object_class_handle_;
ReferenceTypeInfo::TypeHandle class_class_handle_;
+ ReferenceTypeInfo::TypeHandle method_handle_class_handle_;
+ ReferenceTypeInfo::TypeHandle method_type_class_handle_;
ReferenceTypeInfo::TypeHandle string_class_handle_;
ReferenceTypeInfo::TypeHandle throwable_class_handle_;
};
diff --git a/compiler/utils/assembler_thumb_test_expected.cc.inc b/compiler/utils/assembler_thumb_test_expected.cc.inc
index 674dc9a78b..19c405e517 100644
--- a/compiler/utils/assembler_thumb_test_expected.cc.inc
+++ b/compiler/utils/assembler_thumb_test_expected.cc.inc
@@ -153,7 +153,7 @@ const char* const VixlJniHelpersResults[] = {
" 21c: f8d9 8034 ldr.w r8, [r9, #52] ; 0x34\n",
" 220: 4770 bx lr\n",
" 222: 4660 mov r0, ip\n",
- " 224: f8d9 c2c4 ldr.w ip, [r9, #708] ; 0x2c4\n",
+ " 224: f8d9 c2cc ldr.w ip, [r9, #716] ; 0x2cc\n",
" 228: 47e0 blx ip\n",
nullptr
};
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 63518be15f..6b65aca943 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -1257,10 +1257,10 @@ class Dex2Oat FINAL {
if (stored_class_loader_context_ == nullptr) {
Usage("Option --stored-class-loader-context has an incorrect format: %s",
stored_context_arg.c_str());
- } else if (!class_loader_context_->VerifyClassLoaderContextMatch(
+ } else if (class_loader_context_->VerifyClassLoaderContextMatch(
stored_context_arg,
/*verify_names*/ false,
- /*verify_checksums*/ false)) {
+ /*verify_checksums*/ false) != ClassLoaderContext::VerificationResult::kVerifies) {
Usage(
"Option --stored-class-loader-context '%s' mismatches --class-loader-context '%s'",
stored_context_arg.c_str(),
diff --git a/dex2oat/linker/oat_writer_test.cc b/dex2oat/linker/oat_writer_test.cc
index 1699153e7e..df0641cc7f 100644
--- a/dex2oat/linker/oat_writer_test.cc
+++ b/dex2oat/linker/oat_writer_test.cc
@@ -497,7 +497,7 @@ TEST_F(OatTest, OatHeaderSizeCheck) {
EXPECT_EQ(76U, sizeof(OatHeader));
EXPECT_EQ(4U, sizeof(OatMethodOffsets));
EXPECT_EQ(24U, sizeof(OatQuickMethodHeader));
- EXPECT_EQ(162 * static_cast<size_t>(GetInstructionSetPointerSize(kRuntimeISA)),
+ EXPECT_EQ(164 * static_cast<size_t>(GetInstructionSetPointerSize(kRuntimeISA)),
sizeof(QuickEntryPoints));
}
diff --git a/dexlayout/Android.bp b/dexlayout/Android.bp
index 5285c08cc2..b009774582 100644
--- a/dexlayout/Android.bp
+++ b/dexlayout/Android.bp
@@ -27,7 +27,6 @@ art_cc_defaults {
],
export_include_dirs: ["."],
shared_libs: [
- "libartbase",
"libbase",
],
static_libs: ["libz"],
@@ -40,6 +39,7 @@ art_cc_library {
"dex2oat-pgo-defaults",
],
shared_libs: [
+ "libart",
"libdexfile",
"libprofile",
],
@@ -60,6 +60,7 @@ art_cc_library {
"art_debug_defaults",
],
shared_libs: [
+ "libartd",
"libdexfiled",
"libprofiled",
],
@@ -79,9 +80,8 @@ art_cc_binary {
name: "dexlayout",
defaults: ["dexlayout-defaults"],
shared_libs: [
- "libartbase",
- "libdexfile",
"libprofile",
+ "libart",
"libart-dexlayout",
],
}
@@ -93,9 +93,8 @@ art_cc_binary {
"dexlayout-defaults",
],
shared_libs: [
- "libartbased",
- "libdexfiled",
"libprofiled",
+ "libartd",
"libartd-dexlayout",
],
}
diff --git a/dexlayout/dexlayout.cc b/dexlayout/dexlayout.cc
index 03dfee319e..62dd1a9554 100644
--- a/dexlayout/dexlayout.cc
+++ b/dexlayout/dexlayout.cc
@@ -36,8 +36,8 @@
#include "base/logging.h" // For VLOG_IS_ON.
#include "base/mem_map.h"
#include "base/os.h"
-#include "base/unix_file/fd_file.h"
#include "base/utils.h"
+#include "dex/art_dex_file_loader.h"
#include "dex/descriptors_names.h"
#include "dex/dex_file-inl.h"
#include "dex/dex_file_layout.h"
@@ -1930,7 +1930,7 @@ bool DexLayout::ProcessDexFile(const char* file_name,
std::string location = "memory mapped file for " + std::string(file_name);
// Dex file verifier cannot handle compact dex.
bool verify = options_.compact_dex_level_ == CompactDexLevel::kCompactDexLevelNone;
- const DexFileLoader dex_file_loader;
+ const ArtDexFileLoader dex_file_loader;
DexContainer::Section* const main_section = (*dex_container)->GetMainSection();
DexContainer::Section* const data_section = (*dex_container)->GetDataSection();
DCHECK_EQ(file_size, main_section->Size())
@@ -1980,32 +1980,10 @@ int DexLayout::ProcessFile(const char* file_name) {
// all of which are Zip archives with "classes.dex" inside.
const bool verify_checksum = !options_.ignore_bad_checksum_;
std::string error_msg;
- std::unique_ptr<File> input_file(OS::OpenFileForReading(file_name));
- if (input_file == nullptr) {
- LOG(ERROR) << "Could not open file " << file_name << " for reading";
- return -1;
- }
- std::unique_ptr<MemMap> mmap(MemMap::MapFile(input_file->GetLength(),
- PROT_READ,
- MAP_PRIVATE,
- input_file->Fd(),
- /*start*/0,
- /*low_4gb*/false,
- file_name,
- &error_msg));
- if (mmap == nullptr) {
- LOG(ERROR) << "MemMap failed for '" << file_name << "' " << error_msg;
- return -1;
- }
- const DexFileLoader dex_file_loader;
+ const ArtDexFileLoader dex_file_loader;
std::vector<std::unique_ptr<const DexFile>> dex_files;
- if (!dex_file_loader.OpenAll(mmap->Begin(),
- mmap->Size(),
- file_name,
- /*verify*/true,
- verify_checksum,
- &error_msg,
- &dex_files)) {
+ if (!dex_file_loader.Open(
+ file_name, file_name, /* verify */ true, verify_checksum, &error_msg, &dex_files)) {
// Display returned error message to user. Note that this error behavior
// differs from the error messages shown by the original Dalvik dexdump.
LOG(ERROR) << error_msg;
diff --git a/dexlayout/dexlayout_main.cc b/dexlayout/dexlayout_main.cc
index 3f92d501f6..185c1420ab 100644
--- a/dexlayout/dexlayout_main.cc
+++ b/dexlayout/dexlayout_main.cc
@@ -34,6 +34,7 @@
#include "base/logging.h" // For InitLogging.
#include "base/mem_map.h"
#include "profile/profile_compilation_info.h"
+#include "runtime.h"
namespace art {
@@ -65,17 +66,12 @@ static void Usage(void) {
LOG(ERROR) << " -x : compact dex generation level, either 'none' or 'fast'";
}
-NO_RETURN static void Abort(const char* msg) {
- LOG(ERROR) << "Aborted: " << msg;
- exit(1);
-}
-
/*
* Main driver of the dexlayout utility.
*/
int DexlayoutDriver(int argc, char** argv) {
// Art specific set up.
- InitLogging(argv, Abort);
+ InitLogging(argv, Runtime::Abort);
MemMap::Init();
Options options;
diff --git a/libdexfile/dex/dex_file_loader.cc b/libdexfile/dex/dex_file_loader.cc
index 1e0f5ac6ae..457addf114 100644
--- a/libdexfile/dex/dex_file_loader.cc
+++ b/libdexfile/dex/dex_file_loader.cc
@@ -191,6 +191,8 @@ std::string DexFileLoader::GetDexCanonicalLocation(const char* dex_location) {
std::string base_location = GetBaseLocation(dex_location);
const char* suffix = dex_location + base_location.size();
DCHECK(suffix[0] == 0 || suffix[0] == kMultiDexSeparator);
+ // Warning: Bionic implementation of realpath() allocates > 12KB on the stack.
+ // Do not run this code on a small stack, e.g. in signal handler.
UniqueCPtr<const char[]> path(realpath(base_location.c_str(), nullptr));
if (path != nullptr && path.get() != base_location) {
return std::string(path.get()) + suffix;
diff --git a/libdexfile/dex/dex_file_loader.h b/libdexfile/dex/dex_file_loader.h
index 28cdfc13ce..01532203eb 100644
--- a/libdexfile/dex/dex_file_loader.h
+++ b/libdexfile/dex/dex_file_loader.h
@@ -71,7 +71,7 @@ class DexFileLoader {
// of the dex file. In the second case (oat) it will include the file name
// and possibly some multidex annotation to uniquely identify it.
// canonical_dex_location:
- // the dex_location where it's file name part has been made canonical.
+ // the dex_location where its file name part has been made canonical.
static std::string GetDexCanonicalLocation(const char* dex_location);
// For normal dex files, location and base location coincide. If a dex file is part of a multidex
diff --git a/libprofile/Android.bp b/libprofile/Android.bp
index 5afe73b353..bcb90cb680 100644
--- a/libprofile/Android.bp
+++ b/libprofile/Android.bp
@@ -40,6 +40,7 @@ cc_defaults {
],
},
},
+ //generated_sources: ["art_libartbase_operator_srcs"],
cflags: ["-DBUILDING_LIBART=1"],
shared_libs: [
"libartbase",
diff --git a/profman/Android.bp b/profman/Android.bp
index c9c92e6685..3c8c72c34a 100644
--- a/profman/Android.bp
+++ b/profman/Android.bp
@@ -39,7 +39,7 @@ art_cc_binary {
name: "profman",
defaults: ["profman-defaults"],
shared_libs: [
- "libartbase",
+ "libart",
"libprofile",
"libdexfile",
],
@@ -52,7 +52,7 @@ art_cc_binary {
"profman-defaults",
],
shared_libs: [
- "libartbased",
+ "libartd",
"libprofiled",
"libdexfiled",
],
diff --git a/profman/profman.cc b/profman/profman.cc
index c16fadd828..cd88d03929 100644
--- a/profman/profman.cc
+++ b/profman/profman.cc
@@ -18,7 +18,6 @@
#include <stdio.h>
#include <stdlib.h>
#include <sys/file.h>
-#include <sys/mman.h>
#include <sys/param.h>
#include <unistd.h>
@@ -41,6 +40,7 @@
#include "base/utils.h"
#include "base/zip_archive.h"
#include "boot_image_profile.h"
+#include "dex/art_dex_file_loader.h"
#include "dex/bytecode_utils.h"
#include "dex/code_item_accessors-inl.h"
#include "dex/dex_file.h"
@@ -49,6 +49,7 @@
#include "dex/type_reference.h"
#include "profile/profile_compilation_info.h"
#include "profile_assistant.h"
+#include "runtime.h"
namespace art {
@@ -176,11 +177,6 @@ static constexpr char kMethodFlagStringHot = 'H';
static constexpr char kMethodFlagStringStartup = 'S';
static constexpr char kMethodFlagStringPostStartup = 'P';
-NO_RETURN static void Abort(const char* msg) {
- LOG(ERROR) << "Aborted: " << msg;
- exit(1);
-}
-
// TODO(calin): This class has grown too much from its initial design. Split the functionality
// into smaller, more contained pieces.
class ProfMan FINAL {
@@ -206,8 +202,8 @@ class ProfMan FINAL {
original_argc = argc;
original_argv = argv;
- MemMap::Init();
- InitLogging(argv, Abort);
+ Locks::Init();
+ InitLogging(argv, Runtime::Abort);
// Skip over the command name.
argv++;
@@ -417,49 +413,36 @@ class ProfMan FINAL {
}
static constexpr bool kVerifyChecksum = true;
for (size_t i = 0; i < dex_locations_.size(); ++i) {
- std::unique_ptr<File> apk_file;
+ std::string error_msg;
+ const ArtDexFileLoader dex_file_loader;
+ std::vector<std::unique_ptr<const DexFile>> dex_files_for_location;
// We do not need to verify the apk for processing profiles.
if (use_apk_fd_list) {
- apk_file.reset(new File(apks_fd_[i], false/*checkUsage*/));
+ if (dex_file_loader.OpenZip(apks_fd_[i],
+ dex_locations_[i],
+ /* verify */ false,
+ kVerifyChecksum,
+ &error_msg,
+ &dex_files_for_location)) {
+ } else {
+ LOG(ERROR) << "OpenZip failed for '" << dex_locations_[i] << "' " << error_msg;
+ return false;
+ }
} else {
- apk_file.reset(new File(apk_files_[i], O_RDONLY, false/*checkUsage*/));
- if (apk_file == nullptr) {
- LOG(ERROR) << "Open failed for '" << dex_locations_[i] << "' ";
+ if (dex_file_loader.Open(apk_files_[i].c_str(),
+ dex_locations_[i],
+ /* verify */ false,
+ kVerifyChecksum,
+ &error_msg,
+ &dex_files_for_location)) {
+ } else {
+ LOG(ERROR) << "Open failed for '" << dex_locations_[i] << "' " << error_msg;
return false;
}
}
- std::string error_msg;
- std::unique_ptr<MemMap> mmap(MemMap::MapFile(apk_file->GetLength(),
- PROT_READ,
- MAP_PRIVATE,
- apk_file->Fd(),
- /*start*/0,
- /*low_4gb*/false,
- dex_locations_[i].c_str(),
- &error_msg));
- if (mmap == nullptr) {
- LOG(ERROR) << "MemMap failed for '" << dex_locations_[i] << "' " << error_msg;
- return false;
- }
- const DexFileLoader dex_file_loader;
- std::vector<std::unique_ptr<const DexFile>> dex_files_for_location;
- if (!dex_file_loader.OpenAll(mmap->Begin(),
- mmap->Size(),
- dex_locations_[i],
- /* verify */ false,
- kVerifyChecksum,
- &error_msg,
- &dex_files_for_location)) {
- LOG(ERROR) << "OpenAll failed for '" << dex_locations_[i] << "' " << error_msg;
- return false;
- }
for (std::unique_ptr<const DexFile>& dex_file : dex_files_for_location) {
process_fn(std::move(dex_file));
}
- // Leak apk_file and mmap for now.
- // TODO: close fds, etc.
- apk_file.release();
- mmap.release();
}
return true;
}
diff --git a/runtime/Android.bp b/runtime/Android.bp
index 116453b1bf..64e6796ba0 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -422,6 +422,7 @@ gensrcs {
srcs: [
"arch/instruction_set.h",
"base/mutex.h",
+ "class_loader_context.h",
"class_status.h",
"debugger.h",
"gc_root.h",
diff --git a/runtime/arch/arm/instruction_set_features_arm.cc b/runtime/arch/arm/instruction_set_features_arm.cc
index 801254fd30..608999b3bf 100644
--- a/runtime/arch/arm/instruction_set_features_arm.cc
+++ b/runtime/arch/arm/instruction_set_features_arm.cc
@@ -46,9 +46,11 @@ ArmFeaturesUniquePtr ArmInstructionSetFeatures::FromVariant(
"cortex-a53",
"cortex-a53.a57",
"cortex-a53.a72",
+ "cortex-a55",
"cortex-a57",
"cortex-a72",
"cortex-a73",
+ "cortex-a75",
"exynos-m1",
"denver",
"kryo"
diff --git a/runtime/arch/arm/quick_entrypoints_arm.S b/runtime/arch/arm/quick_entrypoints_arm.S
index a930cc494e..cd00125de5 100644
--- a/runtime/arch/arm/quick_entrypoints_arm.S
+++ b/runtime/arch/arm/quick_entrypoints_arm.S
@@ -1015,7 +1015,10 @@ ENTRY \name
END \name
.endm
-// Macro for string and type resolution and initialization.
+ /*
+ * Macro for resolution and initialization of indexed DEX file
+ * constants such as classes and strings.
+ */
.macro ONE_ARG_SAVE_EVERYTHING_DOWNCALL name, entrypoint, runtime_method_offset = RUNTIME_SAVE_EVERYTHING_METHOD_OFFSET
.extern \entrypoint
ENTRY \name
@@ -1040,6 +1043,8 @@ END \name
ONE_ARG_SAVE_EVERYTHING_DOWNCALL_FOR_CLINIT art_quick_initialize_static_storage, artInitializeStaticStorageFromCode
ONE_ARG_SAVE_EVERYTHING_DOWNCALL_FOR_CLINIT art_quick_initialize_type, artInitializeTypeFromCode
ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_initialize_type_and_verify_access, artInitializeTypeAndVerifyAccessFromCode
+ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_resolve_method_handle, artResolveMethodHandleFromCode
+ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_resolve_method_type, artResolveMethodTypeFromCode
ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_resolve_string, artResolveStringFromCode
// Note: Functions `art{Get,Set}<Kind>{Static,Instance}FromCompiledCode` are
diff --git a/runtime/arch/arm64/instruction_set_features_arm64.cc b/runtime/arch/arm64/instruction_set_features_arm64.cc
index 42c9a846d0..d0f61c946c 100644
--- a/runtime/arch/arm64/instruction_set_features_arm64.cc
+++ b/runtime/arch/arm64/instruction_set_features_arm64.cc
@@ -52,6 +52,8 @@ Arm64FeaturesUniquePtr Arm64InstructionSetFeatures::FromVariant(
// Check to see if this is an expected variant.
static const char* arm64_known_variants[] = {
"cortex-a35",
+ "cortex-a55",
+ "cortex-a75",
"exynos-m1",
"exynos-m2",
"exynos-m3",
diff --git a/runtime/arch/arm64/instruction_set_features_arm64_test.cc b/runtime/arch/arm64/instruction_set_features_arm64_test.cc
index 7fd39b6b1b..b946f4f637 100644
--- a/runtime/arch/arm64/instruction_set_features_arm64_test.cc
+++ b/runtime/arch/arm64/instruction_set_features_arm64_test.cc
@@ -64,6 +64,26 @@ TEST(Arm64InstructionSetFeaturesTest, Arm64Features) {
EXPECT_FALSE(kryo_features->Equals(cortex_a57_features.get()));
EXPECT_STREQ("-a53", kryo_features->GetFeatureString().c_str());
EXPECT_EQ(kryo_features->AsBitmap(), 0U);
+
+ std::unique_ptr<const InstructionSetFeatures> cortex_a55_features(
+ InstructionSetFeatures::FromVariant(InstructionSet::kArm64, "cortex-a55", &error_msg));
+ ASSERT_TRUE(cortex_a55_features.get() != nullptr) << error_msg;
+ EXPECT_EQ(cortex_a55_features->GetInstructionSet(), InstructionSet::kArm64);
+ EXPECT_TRUE(cortex_a55_features->Equals(cortex_a55_features.get()));
+ EXPECT_TRUE(cortex_a55_features->Equals(cortex_a35_features.get()));
+ EXPECT_FALSE(cortex_a55_features->Equals(cortex_a57_features.get()));
+ EXPECT_STREQ("-a53", cortex_a55_features->GetFeatureString().c_str());
+ EXPECT_EQ(cortex_a55_features->AsBitmap(), 0U);
+
+ std::unique_ptr<const InstructionSetFeatures> cortex_a75_features(
+ InstructionSetFeatures::FromVariant(InstructionSet::kArm64, "cortex-a75", &error_msg));
+ ASSERT_TRUE(cortex_a75_features.get() != nullptr) << error_msg;
+ EXPECT_EQ(cortex_a75_features->GetInstructionSet(), InstructionSet::kArm64);
+ EXPECT_TRUE(cortex_a75_features->Equals(cortex_a75_features.get()));
+ EXPECT_TRUE(cortex_a75_features->Equals(cortex_a35_features.get()));
+ EXPECT_FALSE(cortex_a75_features->Equals(cortex_a57_features.get()));
+ EXPECT_STREQ("-a53", cortex_a75_features->GetFeatureString().c_str());
+ EXPECT_EQ(cortex_a75_features->AsBitmap(), 0U);
}
} // namespace art
diff --git a/runtime/arch/arm64/quick_entrypoints_arm64.S b/runtime/arch/arm64/quick_entrypoints_arm64.S
index 9ff5ebede3..ac5b2b8b88 100644
--- a/runtime/arch/arm64/quick_entrypoints_arm64.S
+++ b/runtime/arch/arm64/quick_entrypoints_arm64.S
@@ -1533,7 +1533,10 @@ ENTRY \name
END \name
.endm
-// Macro for string and type resolution and initialization.
+ /*
+ * Macro for resolution and initialization of indexed DEX file
+ * constants such as classes and strings.
+ */
.macro ONE_ARG_SAVE_EVERYTHING_DOWNCALL name, entrypoint, runtime_method_offset = RUNTIME_SAVE_EVERYTHING_METHOD_OFFSET
.extern \entrypoint
ENTRY \name
@@ -1577,6 +1580,8 @@ TWO_ARG_REF_DOWNCALL art_quick_handle_fill_data, artHandleFillArrayDataFromCode,
ONE_ARG_SAVE_EVERYTHING_DOWNCALL_FOR_CLINIT art_quick_initialize_static_storage, artInitializeStaticStorageFromCode
ONE_ARG_SAVE_EVERYTHING_DOWNCALL_FOR_CLINIT art_quick_initialize_type, artInitializeTypeFromCode
ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_initialize_type_and_verify_access, artInitializeTypeAndVerifyAccessFromCode
+ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_resolve_method_handle, artResolveMethodHandleFromCode
+ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_resolve_method_type, artResolveMethodTypeFromCode
ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_resolve_string, artResolveStringFromCode
// Note: Functions `art{Get,Set}<Kind>{Static,Instance}FromCompiledCode` are
diff --git a/runtime/arch/mips/entrypoints_init_mips.cc b/runtime/arch/mips/entrypoints_init_mips.cc
index 9418caf98c..5d6e410101 100644
--- a/runtime/arch/mips/entrypoints_init_mips.cc
+++ b/runtime/arch/mips/entrypoints_init_mips.cc
@@ -203,6 +203,10 @@ void InitEntryPoints(JniEntryPoints* jpoints, QuickEntryPoints* qpoints) {
static_assert(!IsDirectEntrypoint(kQuickInitializeType), "Non-direct C stub marked direct.");
qpoints->pResolveString = art_quick_resolve_string;
static_assert(!IsDirectEntrypoint(kQuickResolveString), "Non-direct C stub marked direct.");
+ qpoints->pResolveMethodHandle = art_quick_resolve_method_handle;
+ static_assert(!IsDirectEntrypoint(kQuickResolveMethodHandle), "Non-direct C stub marked direct.");
+ qpoints->pResolveMethodType = art_quick_resolve_method_type;
+ static_assert(!IsDirectEntrypoint(kQuickResolveMethodType), "Non-direct C stub marked direct.");
// Field
qpoints->pSet8Instance = art_quick_set8_instance;
diff --git a/runtime/arch/mips/quick_entrypoints_mips.S b/runtime/arch/mips/quick_entrypoints_mips.S
index d8fe480719..c367ea60c2 100644
--- a/runtime/arch/mips/quick_entrypoints_mips.S
+++ b/runtime/arch/mips/quick_entrypoints_mips.S
@@ -2027,8 +2027,11 @@ GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved16_tlab, artAllocArrayFr
GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved32_tlab, artAllocArrayFromCodeResolvedTLAB, COMPUTE_ARRAY_SIZE_32
GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved64_tlab, artAllocArrayFromCodeResolvedTLAB, COMPUTE_ARRAY_SIZE_64
-// Macro for string and type resolution and initialization.
-// $a0 is both input and output.
+ /*
+ * Macro for resolution and initialization of indexed DEX file
+ * constants such as classes and strings. $a0 is both input and
+ * output.
+ */
.macro ONE_ARG_SAVE_EVERYTHING_DOWNCALL name, entrypoint, runtime_method_offset = RUNTIME_SAVE_EVERYTHING_METHOD_OFFSET
.extern \entrypoint
ENTRY_NO_GP \name
@@ -2053,6 +2056,18 @@ END \name
.endm
/*
+ * Entry from managed code to resolve a method handle. On entry, A0 holds the method handle
+ * index. On success the MethodHandle is returned, otherwise an exception is raised.
+ */
+ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_resolve_method_handle, artResolveMethodHandleFromCode
+
+ /*
+ * Entry from managed code to resolve a method type. On entry, A0 holds the method type index.
+ * On success the MethodType is returned, otherwise an exception is raised.
+ */
+ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_resolve_method_type, artResolveMethodTypeFromCode
+
+ /*
* Entry from managed code to resolve a string, this stub will allocate a String and deliver an
* exception on error. On success the String is returned. A0 holds the string index. The fast
* path check for hit in strings cache has already been performed.
diff --git a/runtime/arch/mips64/quick_entrypoints_mips64.S b/runtime/arch/mips64/quick_entrypoints_mips64.S
index 8d2a7bd6c1..1f4f174e26 100644
--- a/runtime/arch/mips64/quick_entrypoints_mips64.S
+++ b/runtime/arch/mips64/quick_entrypoints_mips64.S
@@ -1930,8 +1930,11 @@ GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved16_tlab, artAllocArrayFr
GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved32_tlab, artAllocArrayFromCodeResolvedTLAB, COMPUTE_ARRAY_SIZE_32
GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved64_tlab, artAllocArrayFromCodeResolvedTLAB, COMPUTE_ARRAY_SIZE_64
-// Macro for string and type resolution and initialization.
-// $a0 is both input and output.
+ /*
+ * Macro for resolution and initialization of indexed DEX file
+ * constants such as classes and strings. $a0 is both input and
+ * output.
+ */
.macro ONE_ARG_SAVE_EVERYTHING_DOWNCALL name, entrypoint, runtime_method_offset = RUNTIME_SAVE_EVERYTHING_METHOD_OFFSET
.extern \entrypoint
ENTRY_NO_GP \name
@@ -1953,6 +1956,18 @@ END \name
.endm
/*
+ * Entry from managed code to resolve a method handle. On entry, A0 holds the method handle
+ * index. On success the MethodHandle is returned, otherwise an exception is raised.
+ */
+ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_resolve_method_handle, artResolveMethodHandleFromCode
+
+ /*
+ * Entry from managed code to resolve a method type. On entry, A0 holds the method type index.
+ * On success the MethodType is returned, otherwise an exception is raised.
+ */
+ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_resolve_method_type, artResolveMethodTypeFromCode
+
+ /*
* Entry from managed code to resolve a string, this stub will allocate a String and deliver an
* exception on error. On success the String is returned. A0 holds the string index. The fast
* path check for hit in strings cache has already been performed.
diff --git a/runtime/arch/x86/quick_entrypoints_x86.S b/runtime/arch/x86/quick_entrypoints_x86.S
index df43aef94b..8ab4ce160f 100644
--- a/runtime/arch/x86/quick_entrypoints_x86.S
+++ b/runtime/arch/x86/quick_entrypoints_x86.S
@@ -923,7 +923,10 @@ MACRO3(THREE_ARG_REF_DOWNCALL, c_name, cxx_name, return_macro)
END_FUNCTION VAR(c_name)
END_MACRO
-// Macro for string and type resolution and initialization.
+ /*
+ * Macro for resolution and initialization of indexed DEX file
+ * constants such as classes and strings.
+ */
MACRO3(ONE_ARG_SAVE_EVERYTHING_DOWNCALL, c_name, cxx_name, runtime_method_offset = RUNTIME_SAVE_EVERYTHING_METHOD_OFFSET)
DEFINE_FUNCTION VAR(c_name)
SETUP_SAVE_EVERYTHING_FRAME ebx, ebx, \runtime_method_offset // save ref containing registers for GC
@@ -932,7 +935,7 @@ MACRO3(ONE_ARG_SAVE_EVERYTHING_DOWNCALL, c_name, cxx_name, runtime_method_offset
CFI_ADJUST_CFA_OFFSET(8)
pushl %fs:THREAD_SELF_OFFSET // pass Thread::Current()
CFI_ADJUST_CFA_OFFSET(4)
- PUSH eax // pass arg1
+ PUSH eax // pass the index of the constant as arg1
call CALLVAR(cxx_name) // cxx_name(arg1, Thread*)
addl MACRO_LITERAL(16), %esp // pop arguments
CFI_ADJUST_CFA_OFFSET(-16)
@@ -1278,6 +1281,8 @@ GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved64_tlab, artAllocArrayFr
ONE_ARG_SAVE_EVERYTHING_DOWNCALL_FOR_CLINIT art_quick_initialize_static_storage, artInitializeStaticStorageFromCode
ONE_ARG_SAVE_EVERYTHING_DOWNCALL_FOR_CLINIT art_quick_initialize_type, artInitializeTypeFromCode
ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_initialize_type_and_verify_access, artInitializeTypeAndVerifyAccessFromCode
+ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_resolve_method_handle, artResolveMethodHandleFromCode
+ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_resolve_method_type, artResolveMethodTypeFromCode
ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_resolve_string, artResolveStringFromCode
TWO_ARG_REF_DOWNCALL art_quick_handle_fill_data, artHandleFillArrayDataFromCode, RETURN_IF_EAX_ZERO
diff --git a/runtime/arch/x86_64/quick_entrypoints_x86_64.S b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
index 4f941e1c48..eb945ed366 100644
--- a/runtime/arch/x86_64/quick_entrypoints_x86_64.S
+++ b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
@@ -951,12 +951,15 @@ MACRO3(THREE_ARG_REF_DOWNCALL, c_name, cxx_name, return_macro)
END_FUNCTION VAR(c_name)
END_MACRO
-// Macro for string and type resolution and initialization.
+ /*
+ * Macro for resolution and initialization of indexed DEX file
+ * constants such as classes and strings.
+ */
MACRO3(ONE_ARG_SAVE_EVERYTHING_DOWNCALL, c_name, cxx_name, runtime_method_offset = RUNTIME_SAVE_EVERYTHING_METHOD_OFFSET)
DEFINE_FUNCTION VAR(c_name)
SETUP_SAVE_EVERYTHING_FRAME \runtime_method_offset // save everything for GC
// Outgoing argument set up
- movl %eax, %edi // pass string index
+ movl %eax, %edi // pass the index of the constant as arg0
movq %gs:THREAD_SELF_OFFSET, %rsi // pass Thread::Current()
call CALLVAR(cxx_name) // cxx_name(arg0, Thread*)
testl %eax, %eax // If result is null, deliver the OOME.
@@ -1298,6 +1301,8 @@ END_FUNCTION art_quick_alloc_object_initialized_region_tlab
ONE_ARG_SAVE_EVERYTHING_DOWNCALL_FOR_CLINIT art_quick_initialize_static_storage, artInitializeStaticStorageFromCode
ONE_ARG_SAVE_EVERYTHING_DOWNCALL_FOR_CLINIT art_quick_initialize_type, artInitializeTypeFromCode
ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_initialize_type_and_verify_access, artInitializeTypeAndVerifyAccessFromCode
+ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_resolve_method_handle, artResolveMethodHandleFromCode
+ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_resolve_method_type, artResolveMethodTypeFromCode
ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_resolve_string, artResolveStringFromCode
TWO_ARG_REF_DOWNCALL art_quick_handle_fill_data, artHandleFillArrayDataFromCode, RETURN_IF_EAX_ZERO
diff --git a/runtime/asm_support.h b/runtime/asm_support.h
index 2f7d6ab98f..70ff40d32c 100644
--- a/runtime/asm_support.h
+++ b/runtime/asm_support.h
@@ -73,7 +73,7 @@ ADD_TEST_EQ(THREAD_LOCAL_OBJECTS_OFFSET,
// Offset of field Thread::tlsPtr_.mterp_current_ibase.
#define THREAD_CURRENT_IBASE_OFFSET \
- (THREAD_LOCAL_OBJECTS_OFFSET + __SIZEOF_SIZE_T__ + (1 + 162) * __SIZEOF_POINTER__)
+ (THREAD_LOCAL_OBJECTS_OFFSET + __SIZEOF_SIZE_T__ + (1 + 164) * __SIZEOF_POINTER__)
ADD_TEST_EQ(THREAD_CURRENT_IBASE_OFFSET,
art::Thread::MterpCurrentIBaseOffset<POINTER_SIZE>().Int32Value())
// Offset of field Thread::tlsPtr_.mterp_default_ibase.
diff --git a/runtime/base/file_utils.cc b/runtime/base/file_utils.cc
index 7921985b15..537216c198 100644
--- a/runtime/base/file_utils.cc
+++ b/runtime/base/file_utils.cc
@@ -261,12 +261,12 @@ std::string ReplaceFileExtension(const std::string& filename, const std::string&
}
}
-bool LocationIsOnSystem(const char* location) {
- UniqueCPtr<const char[]> path(realpath(location, nullptr));
- return path != nullptr && android::base::StartsWith(path.get(), GetAndroidRoot().c_str());
+bool LocationIsOnSystem(const char* path) {
+ UniqueCPtr<const char[]> full_path(realpath(path, nullptr));
+ return path != nullptr && android::base::StartsWith(full_path.get(), GetAndroidRoot().c_str());
}
-bool LocationIsOnSystemFramework(const char* location) {
+bool LocationIsOnSystemFramework(const char* full_path) {
std::string error_msg;
std::string root_path = GetAndroidRootSafe(&error_msg);
if (root_path.empty()) {
@@ -275,12 +275,7 @@ bool LocationIsOnSystemFramework(const char* location) {
return false;
}
std::string framework_path = root_path + "/framework/";
-
- // Warning: Bionic implementation of realpath() allocates > 12KB on the stack.
- // Do not run this code on a small stack, e.g. in signal handler.
- UniqueCPtr<const char[]> path(realpath(location, nullptr));
- return path != nullptr &&
- android::base::StartsWith(path.get(), framework_path.c_str());
+ return android::base::StartsWith(full_path, framework_path);
}
} // namespace art
diff --git a/runtime/class_loader_context.cc b/runtime/class_loader_context.cc
index 98174142f1..2bd541118b 100644
--- a/runtime/class_loader_context.cc
+++ b/runtime/class_loader_context.cc
@@ -672,9 +672,10 @@ static bool IsAbsoluteLocation(const std::string& location) {
return !location.empty() && location[0] == '/';
}
-bool ClassLoaderContext::VerifyClassLoaderContextMatch(const std::string& context_spec,
- bool verify_names,
- bool verify_checksums) const {
+ClassLoaderContext::VerificationResult ClassLoaderContext::VerifyClassLoaderContextMatch(
+ const std::string& context_spec,
+ bool verify_names,
+ bool verify_checksums) const {
if (verify_names || verify_checksums) {
DCHECK(dex_files_open_attempted_);
DCHECK(dex_files_open_result_);
@@ -683,15 +684,21 @@ bool ClassLoaderContext::VerifyClassLoaderContextMatch(const std::string& contex
ClassLoaderContext expected_context;
if (!expected_context.Parse(context_spec, verify_checksums)) {
LOG(WARNING) << "Invalid class loader context: " << context_spec;
- return false;
+ return VerificationResult::kMismatch;
}
// Special shared library contexts always match. They essentially instruct the runtime
// to ignore the class path check because the oat file is known to be loaded in different
// contexts. OatFileManager will further verify if the oat file can be loaded based on the
// collision check.
- if (special_shared_library_ || expected_context.special_shared_library_) {
- return true;
+ if (expected_context.special_shared_library_) {
+ // Special case where we are the only entry in the class path.
+ if (class_loader_chain_.size() == 1 && class_loader_chain_[0].classpath.size() == 0) {
+ return VerificationResult::kVerifies;
+ }
+ return VerificationResult::kForcedToSkipChecks;
+ } else if (special_shared_library_) {
+ return VerificationResult::kForcedToSkipChecks;
}
if (expected_context.class_loader_chain_.size() != class_loader_chain_.size()) {
@@ -699,7 +706,7 @@ bool ClassLoaderContext::VerifyClassLoaderContextMatch(const std::string& contex
<< expected_context.class_loader_chain_.size()
<< ", actual=" << class_loader_chain_.size()
<< " (" << context_spec << " | " << EncodeContextForOatFile("") << ")";
- return false;
+ return VerificationResult::kMismatch;
}
for (size_t i = 0; i < class_loader_chain_.size(); i++) {
@@ -710,14 +717,14 @@ bool ClassLoaderContext::VerifyClassLoaderContextMatch(const std::string& contex
<< ". expected=" << GetClassLoaderTypeName(expected_info.type)
<< ", found=" << GetClassLoaderTypeName(info.type)
<< " (" << context_spec << " | " << EncodeContextForOatFile("") << ")";
- return false;
+ return VerificationResult::kMismatch;
}
if (info.classpath.size() != expected_info.classpath.size()) {
LOG(WARNING) << "ClassLoaderContext classpath size mismatch for position " << i
<< ". expected=" << expected_info.classpath.size()
<< ", found=" << info.classpath.size()
<< " (" << context_spec << " | " << EncodeContextForOatFile("") << ")";
- return false;
+ return VerificationResult::kMismatch;
}
if (verify_checksums) {
@@ -772,7 +779,7 @@ bool ClassLoaderContext::VerifyClassLoaderContextMatch(const std::string& contex
<< ". expected=" << expected_info.classpath[k]
<< ", found=" << info.classpath[k]
<< " (" << context_spec << " | " << EncodeContextForOatFile("") << ")";
- return false;
+ return VerificationResult::kMismatch;
}
// Compare the checksums.
@@ -781,11 +788,11 @@ bool ClassLoaderContext::VerifyClassLoaderContextMatch(const std::string& contex
<< ". expected=" << expected_info.checksums[k]
<< ", found=" << info.checksums[k]
<< " (" << context_spec << " | " << EncodeContextForOatFile("") << ")";
- return false;
+ return VerificationResult::kMismatch;
}
}
}
- return true;
+ return VerificationResult::kVerifies;
}
jclass ClassLoaderContext::GetClassLoaderClass(ClassLoaderType type) {
diff --git a/runtime/class_loader_context.h b/runtime/class_loader_context.h
index 1c83007f41..a4268aa09a 100644
--- a/runtime/class_loader_context.h
+++ b/runtime/class_loader_context.h
@@ -22,8 +22,10 @@
#include "arch/instruction_set.h"
#include "base/dchecked_vector.h"
+#include "dex/dex_file.h"
#include "handle_scope.h"
#include "mirror/class_loader.h"
+#include "oat_file.h"
#include "scoped_thread_state_change.h"
namespace art {
@@ -34,6 +36,18 @@ class OatFile;
// Utility class which holds the class loader context used during compilation/verification.
class ClassLoaderContext {
public:
+ enum class VerificationResult {
+ kVerifies,
+ kForcedToSkipChecks,
+ kMismatch,
+ };
+
+ enum ClassLoaderType {
+ kInvalidClassLoader = 0,
+ kPathClassLoader = 1,
+ kDelegateLastClassLoader = 2
+ };
+
~ClassLoaderContext();
// Opens requested class path files and appends them to ClassLoaderInfo::opened_dex_files.
@@ -109,7 +123,7 @@ class ClassLoaderContext {
// This should be called after OpenDexFiles().
// Names are only verified if verify_names is true.
// Checksums are only verified if verify_checksums is true.
- bool VerifyClassLoaderContextMatch(const std::string& context_spec,
+ VerificationResult VerifyClassLoaderContextMatch(const std::string& context_spec,
bool verify_names = true,
bool verify_checksums = true) const;
@@ -141,12 +155,6 @@ class ClassLoaderContext {
static std::unique_ptr<ClassLoaderContext> Default();
private:
- enum ClassLoaderType {
- kInvalidClassLoader = 0,
- kPathClassLoader = 1,
- kDelegateLastClassLoader = 2
- };
-
struct ClassLoaderInfo {
// The type of this class loader.
ClassLoaderType type;
diff --git a/runtime/class_loader_context_test.cc b/runtime/class_loader_context_test.cc
index 4689ae4c3f..5e3f48c100 100644
--- a/runtime/class_loader_context_test.cc
+++ b/runtime/class_loader_context_test.cc
@@ -608,6 +608,17 @@ TEST_F(ClassLoaderContextTest, CreateContextForClassLoader) {
VerifyClassLoaderPCLFromTestDex(context.get(), 3, "ForClassLoaderA");
}
+
+TEST_F(ClassLoaderContextTest, VerifyClassLoaderContextFirstElement) {
+ std::string context_spec = "PCL[]";
+ std::unique_ptr<ClassLoaderContext> context = ParseContextWithChecksums(context_spec);
+ ASSERT_TRUE(context != nullptr);
+ PretendContextOpenedDexFiles(context.get());
+ // Ensure that the special shared library marks as verified for the first thing in the class path.
+ ASSERT_EQ(context->VerifyClassLoaderContextMatch(OatFile::kSpecialSharedLibrary),
+ ClassLoaderContext::VerificationResult::kVerifies);
+}
+
TEST_F(ClassLoaderContextTest, VerifyClassLoaderContextMatch) {
std::string context_spec = "PCL[a.dex*123:b.dex*456];DLC[c.dex*890]";
std::unique_ptr<ClassLoaderContext> context = ParseContextWithChecksums(context_spec);
@@ -619,28 +630,36 @@ TEST_F(ClassLoaderContextTest, VerifyClassLoaderContextMatch) {
VerifyClassLoaderPCL(context.get(), 0, "a.dex:b.dex");
VerifyClassLoaderDLC(context.get(), 1, "c.dex");
- ASSERT_TRUE(context->VerifyClassLoaderContextMatch(context_spec));
+ ASSERT_EQ(context->VerifyClassLoaderContextMatch(context_spec),
+ ClassLoaderContext::VerificationResult::kVerifies);
std::string wrong_class_loader_type = "PCL[a.dex*123:b.dex*456];PCL[c.dex*890]";
- ASSERT_FALSE(context->VerifyClassLoaderContextMatch(wrong_class_loader_type));
+ ASSERT_EQ(context->VerifyClassLoaderContextMatch(wrong_class_loader_type),
+ ClassLoaderContext::VerificationResult::kMismatch);
std::string wrong_class_loader_order = "DLC[c.dex*890];PCL[a.dex*123:b.dex*456]";
- ASSERT_FALSE(context->VerifyClassLoaderContextMatch(wrong_class_loader_order));
+ ASSERT_EQ(context->VerifyClassLoaderContextMatch(wrong_class_loader_order),
+ ClassLoaderContext::VerificationResult::kMismatch);
std::string wrong_classpath_order = "PCL[b.dex*456:a.dex*123];DLC[c.dex*890]";
- ASSERT_FALSE(context->VerifyClassLoaderContextMatch(wrong_classpath_order));
+ ASSERT_EQ(context->VerifyClassLoaderContextMatch(wrong_classpath_order),
+ ClassLoaderContext::VerificationResult::kMismatch);
std::string wrong_checksum = "PCL[a.dex*999:b.dex*456];DLC[c.dex*890]";
- ASSERT_FALSE(context->VerifyClassLoaderContextMatch(wrong_checksum));
+ ASSERT_EQ(context->VerifyClassLoaderContextMatch(wrong_checksum),
+ ClassLoaderContext::VerificationResult::kMismatch);
std::string wrong_extra_class_loader = "PCL[a.dex*123:b.dex*456];DLC[c.dex*890];PCL[d.dex*321]";
- ASSERT_FALSE(context->VerifyClassLoaderContextMatch(wrong_extra_class_loader));
+ ASSERT_EQ(context->VerifyClassLoaderContextMatch(wrong_extra_class_loader),
+ ClassLoaderContext::VerificationResult::kMismatch);
std::string wrong_extra_classpath = "PCL[a.dex*123:b.dex*456];DLC[c.dex*890:d.dex*321]";
- ASSERT_FALSE(context->VerifyClassLoaderContextMatch(wrong_extra_classpath));
+ ASSERT_EQ(context->VerifyClassLoaderContextMatch(wrong_extra_classpath),
+ ClassLoaderContext::VerificationResult::kMismatch);
std::string wrong_spec = "PCL[a.dex*999:b.dex*456];DLC[";
- ASSERT_FALSE(context->VerifyClassLoaderContextMatch(wrong_spec));
+ ASSERT_EQ(context->VerifyClassLoaderContextMatch(wrong_spec),
+ ClassLoaderContext::VerificationResult::kMismatch);
}
TEST_F(ClassLoaderContextTest, VerifyClassLoaderContextMatchAfterEncoding) {
@@ -652,7 +671,8 @@ TEST_F(ClassLoaderContextTest, VerifyClassLoaderContextMatchAfterEncoding) {
std::unique_ptr<ClassLoaderContext> context = CreateContextForClassLoader(class_loader_d);
std::string context_with_no_base_dir = context->EncodeContextForOatFile("");
- ASSERT_TRUE(context->VerifyClassLoaderContextMatch(context_with_no_base_dir));
+ ASSERT_EQ(context->VerifyClassLoaderContextMatch(context_with_no_base_dir),
+ ClassLoaderContext::VerificationResult::kVerifies);
std::string dex_location = GetTestDexFileName("ForClassLoaderA");
size_t pos = dex_location.rfind('/');
@@ -661,7 +681,8 @@ TEST_F(ClassLoaderContextTest, VerifyClassLoaderContextMatchAfterEncoding) {
std::string context_with_base_dir = context->EncodeContextForOatFile(parent);
ASSERT_NE(context_with_base_dir, context_with_no_base_dir);
- ASSERT_TRUE(context->VerifyClassLoaderContextMatch(context_with_base_dir));
+ ASSERT_EQ(context->VerifyClassLoaderContextMatch(context_with_base_dir),
+ ClassLoaderContext::VerificationResult::kVerifies);
}
TEST_F(ClassLoaderContextTest, VerifyClassLoaderContextMatchAfterEncodingMultidex) {
@@ -669,7 +690,8 @@ TEST_F(ClassLoaderContextTest, VerifyClassLoaderContextMatchAfterEncodingMultide
std::unique_ptr<ClassLoaderContext> context = CreateContextForClassLoader(class_loader);
- ASSERT_TRUE(context->VerifyClassLoaderContextMatch(context->EncodeContextForOatFile("")));
+ ASSERT_EQ(context->VerifyClassLoaderContextMatch(context->EncodeContextForOatFile("")),
+ ClassLoaderContext::VerificationResult::kVerifies);
}
} // namespace art
diff --git a/runtime/dex/art_dex_file_loader.cc b/runtime/dex/art_dex_file_loader.cc
index 415e451098..392ce1e7f5 100644
--- a/runtime/dex/art_dex_file_loader.cc
+++ b/runtime/dex/art_dex_file_loader.cc
@@ -534,7 +534,10 @@ std::unique_ptr<DexFile> ArtDexFileLoader::OpenCommon(const uint8_t* base,
// Check if this dex file is located in the framework directory.
// If it is, set a flag on the dex file. This is used by hidden API
// policy decision logic.
- if (dex_file != nullptr && LocationIsOnSystemFramework(location.c_str())) {
+ // Location can contain multidex suffix, so fetch its canonical version. Note
+ // that this will call `realpath`.
+ std::string path = DexFileLoader::GetDexCanonicalLocation(location.c_str());
+ if (dex_file != nullptr && LocationIsOnSystemFramework(path.c_str())) {
dex_file->SetIsPlatformDexFile();
}
diff --git a/runtime/dex/art_dex_file_loader_test.cc b/runtime/dex/art_dex_file_loader_test.cc
index aee397b65b..274a6df702 100644
--- a/runtime/dex/art_dex_file_loader_test.cc
+++ b/runtime/dex/art_dex_file_loader_test.cc
@@ -49,20 +49,31 @@ class ArtDexFileLoaderTest : public CommonRuntimeTest {
CommonRuntimeTest::SetUp();
std::string dex_location = GetTestDexFileName("Main");
+ std::string multidex_location = GetTestDexFileName("MultiDex");
data_location_path_ = android_data_ + "/foo.jar";
system_location_path_ = GetAndroidRoot() + "/foo.jar";
system_framework_location_path_ = GetAndroidRoot() + "/framework/foo.jar";
+ data_multi_location_path_ = android_data_ + "/multifoo.jar";
+ system_multi_location_path_ = GetAndroidRoot() + "/multifoo.jar";
+ system_framework_multi_location_path_ = GetAndroidRoot() + "/framework/multifoo.jar";
Copy(dex_location, data_location_path_);
Copy(dex_location, system_location_path_);
Copy(dex_location, system_framework_location_path_);
+
+ Copy(multidex_location, data_multi_location_path_);
+ Copy(multidex_location, system_multi_location_path_);
+ Copy(multidex_location, system_framework_multi_location_path_);
}
virtual void TearDown() {
remove(data_location_path_.c_str());
remove(system_location_path_.c_str());
remove(system_framework_location_path_.c_str());
+ remove(data_multi_location_path_.c_str());
+ remove(system_multi_location_path_.c_str());
+ remove(system_framework_multi_location_path_.c_str());
CommonRuntimeTest::TearDown();
}
@@ -70,6 +81,9 @@ class ArtDexFileLoaderTest : public CommonRuntimeTest {
std::string data_location_path_;
std::string system_location_path_;
std::string system_framework_location_path_;
+ std::string data_multi_location_path_;
+ std::string system_multi_location_path_;
+ std::string system_framework_multi_location_path_;
};
// TODO: Port OpenTestDexFile(s) need to be ported to use non-ART utilities, and
@@ -390,6 +404,53 @@ TEST_F(ArtDexFileLoaderTest, IsPlatformDexFile) {
for (std::unique_ptr<const DexFile>& dex_file : dex_files) {
ASSERT_TRUE(dex_file->IsPlatformDexFile());
}
+
+ dex_files.clear();
+
+ // Load multidex file from a non-system directory and check that it is not flagged as framework.
+ success = loader.Open(data_multi_location_path_.c_str(),
+ data_multi_location_path_,
+ /* verify */ false,
+ /* verify_checksum */ false,
+ &error_msg,
+ &dex_files);
+ ASSERT_TRUE(success) << error_msg;
+ ASSERT_GT(dex_files.size(), 1u);
+ for (std::unique_ptr<const DexFile>& dex_file : dex_files) {
+ ASSERT_FALSE(dex_file->IsPlatformDexFile());
+ }
+
+ dex_files.clear();
+
+ // Load multidex file from a system, non-framework directory and check that it is not flagged
+ // as framework.
+ success = loader.Open(system_multi_location_path_.c_str(),
+ system_multi_location_path_,
+ /* verify */ false,
+ /* verify_checksum */ false,
+ &error_msg,
+ &dex_files);
+ ASSERT_TRUE(success);
+ ASSERT_GT(dex_files.size(), 1u);
+ for (std::unique_ptr<const DexFile>& dex_file : dex_files) {
+ ASSERT_FALSE(dex_file->IsPlatformDexFile());
+ }
+
+ dex_files.clear();
+
+ // Load multidex file from a system/framework directory and check that it is flagged as a
+ // framework dex.
+ success = loader.Open(system_framework_multi_location_path_.c_str(),
+ system_framework_multi_location_path_,
+ /* verify */ false,
+ /* verify_checksum */ false,
+ &error_msg,
+ &dex_files);
+ ASSERT_TRUE(success);
+ ASSERT_GT(dex_files.size(), 1u);
+ for (std::unique_ptr<const DexFile>& dex_file : dex_files) {
+ ASSERT_TRUE(dex_file->IsPlatformDexFile());
+ }
}
} // namespace art
diff --git a/runtime/entrypoints/entrypoint_utils.cc b/runtime/entrypoints/entrypoint_utils.cc
index 246c703e93..a58946ae66 100644
--- a/runtime/entrypoints/entrypoint_utils.cc
+++ b/runtime/entrypoints/entrypoint_utils.cc
@@ -260,4 +260,26 @@ ArtMethod* GetCalleeSaveOuterMethod(Thread* self, CalleeSaveType type) {
return DoGetCalleeSaveMethodOuterCallerAndPc(sp, type).first;
}
+ObjPtr<mirror::MethodHandle> ResolveMethodHandleFromCode(ArtMethod* referrer,
+ uint32_t method_handle_idx) {
+ Thread::PoisonObjectPointersIfDebug();
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ return class_linker->ResolveMethodHandle(Thread::Current(), method_handle_idx, referrer);
+}
+
+ObjPtr<mirror::MethodType> ResolveMethodTypeFromCode(ArtMethod* referrer,
+ uint32_t proto_idx) {
+ Thread::PoisonObjectPointersIfDebug();
+ ObjPtr<mirror::MethodType> method_type =
+ referrer->GetDexCache()->GetResolvedMethodType(proto_idx);
+ if (UNLIKELY(method_type == nullptr)) {
+ StackHandleScope<2> hs(Thread::Current());
+ Handle<mirror::DexCache> dex_cache(hs.NewHandle(referrer->GetDexCache()));
+ Handle<mirror::ClassLoader> class_loader(hs.NewHandle(referrer->GetClassLoader()));
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ method_type = class_linker->ResolveMethodType(hs.Self(), proto_idx, dex_cache, class_loader);
+ }
+ return method_type;
+}
+
} // namespace art
diff --git a/runtime/entrypoints/entrypoint_utils.h b/runtime/entrypoints/entrypoint_utils.h
index eb32153b16..0a3b5dfc93 100644
--- a/runtime/entrypoints/entrypoint_utils.h
+++ b/runtime/entrypoints/entrypoint_utils.h
@@ -34,6 +34,8 @@ namespace art {
namespace mirror {
class Array;
class Class;
+class MethodHandle;
+class MethodType;
class Object;
class String;
} // namespace mirror
@@ -151,6 +153,15 @@ inline ObjPtr<mirror::Class> ResolveVerifyAndClinit(dex::TypeIndex type_idx,
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!Roles::uninterruptible_);
+ObjPtr<mirror::MethodHandle> ResolveMethodHandleFromCode(ArtMethod* referrer,
+ uint32_t method_handle_idx)
+ REQUIRES_SHARED(Locks::mutator_lock_)
+ REQUIRES(!Roles::uninterruptible_);
+
+ObjPtr<mirror::MethodType> ResolveMethodTypeFromCode(ArtMethod* referrer, uint32_t proto_idx)
+ REQUIRES_SHARED(Locks::mutator_lock_)
+ REQUIRES(!Roles::uninterruptible_);
+
inline ObjPtr<mirror::String> ResolveStringFromCode(ArtMethod* referrer,
dex::StringIndex string_idx)
REQUIRES_SHARED(Locks::mutator_lock_)
diff --git a/runtime/entrypoints/quick/quick_default_externs.h b/runtime/entrypoints/quick/quick_default_externs.h
index 2d0932a0c4..1804d9e64d 100644
--- a/runtime/entrypoints/quick/quick_default_externs.h
+++ b/runtime/entrypoints/quick/quick_default_externs.h
@@ -37,6 +37,8 @@ extern "C" void art_quick_check_instance_of(art::mirror::Object*, art::mirror::C
extern "C" void* art_quick_initialize_static_storage(uint32_t);
extern "C" void* art_quick_initialize_type(uint32_t);
extern "C" void* art_quick_initialize_type_and_verify_access(uint32_t);
+extern "C" void* art_quick_resolve_method_handle(uint32_t);
+extern "C" void* art_quick_resolve_method_type(uint32_t);
extern "C" void* art_quick_resolve_string(uint32_t);
// Field entrypoints.
diff --git a/runtime/entrypoints/quick/quick_default_init_entrypoints.h b/runtime/entrypoints/quick/quick_default_init_entrypoints.h
index 8c90800463..3f66045576 100644
--- a/runtime/entrypoints/quick/quick_default_init_entrypoints.h
+++ b/runtime/entrypoints/quick/quick_default_init_entrypoints.h
@@ -37,6 +37,8 @@ static void DefaultInitEntryPoints(JniEntryPoints* jpoints, QuickEntryPoints* qp
qpoints->pInitializeStaticStorage = art_quick_initialize_static_storage;
qpoints->pInitializeTypeAndVerifyAccess = art_quick_initialize_type_and_verify_access;
qpoints->pInitializeType = art_quick_initialize_type;
+ qpoints->pResolveMethodHandle = art_quick_resolve_method_handle;
+ qpoints->pResolveMethodType = art_quick_resolve_method_type;
qpoints->pResolveString = art_quick_resolve_string;
// Field
diff --git a/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc b/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc
index cfb427f1ac..cf9ddd8aa8 100644
--- a/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc
@@ -183,6 +183,27 @@ extern "C" mirror::Class* artInitializeTypeAndVerifyAccessFromCode(uint32_t type
return result.Ptr();
}
+extern "C" mirror::MethodHandle* artResolveMethodHandleFromCode(uint32_t method_handle_idx,
+ Thread* self)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ ScopedQuickEntrypointChecks sqec(self);
+ auto caller_and_outer =
+ GetCalleeSaveMethodCallerAndOuterMethod(self, CalleeSaveType::kSaveEverything);
+ ArtMethod* caller = caller_and_outer.caller;
+ ObjPtr<mirror::MethodHandle> result = ResolveMethodHandleFromCode(caller, method_handle_idx);
+ return result.Ptr();
+}
+
+extern "C" mirror::MethodType* artResolveMethodTypeFromCode(uint32_t proto_idx, Thread* self)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ ScopedQuickEntrypointChecks sqec(self);
+ auto caller_and_outer = GetCalleeSaveMethodCallerAndOuterMethod(self,
+ CalleeSaveType::kSaveEverything);
+ ArtMethod* caller = caller_and_outer.caller;
+ ObjPtr<mirror::MethodType> result = ResolveMethodTypeFromCode(caller, proto_idx);
+ return result.Ptr();
+}
+
extern "C" mirror::String* artResolveStringFromCode(int32_t string_idx, Thread* self)
REQUIRES_SHARED(Locks::mutator_lock_) {
ScopedQuickEntrypointChecks sqec(self);
diff --git a/runtime/entrypoints/quick/quick_entrypoints_list.h b/runtime/entrypoints/quick/quick_entrypoints_list.h
index 48a56f2fbf..3a8faca11d 100644
--- a/runtime/entrypoints/quick/quick_entrypoints_list.h
+++ b/runtime/entrypoints/quick/quick_entrypoints_list.h
@@ -38,6 +38,8 @@
V(InitializeStaticStorage, void*, uint32_t) \
V(InitializeTypeAndVerifyAccess, void*, uint32_t) \
V(InitializeType, void*, uint32_t) \
+ V(ResolveMethodHandle, void*, uint32_t) \
+ V(ResolveMethodType, void*, uint32_t) \
V(ResolveString, void*, uint32_t) \
\
V(Set8Instance, int, uint32_t, void*, int8_t) \
diff --git a/runtime/entrypoints_order_test.cc b/runtime/entrypoints_order_test.cc
index 1fdf439d3f..1337cd5fb2 100644
--- a/runtime/entrypoints_order_test.cc
+++ b/runtime/entrypoints_order_test.cc
@@ -183,7 +183,9 @@ class EntrypointsOrderTest : public CommonRuntimeTest {
sizeof(void*));
EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pInitializeTypeAndVerifyAccess, pInitializeType,
sizeof(void*));
- EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pInitializeType, pResolveString, sizeof(void*));
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pInitializeType, pResolveMethodHandle, sizeof(void*));
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pResolveMethodHandle, pResolveMethodType, sizeof(void*));
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pResolveMethodType, pResolveString, sizeof(void*));
EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pResolveString, pSet8Instance, sizeof(void*));
EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pSet8Instance, pSet8Static, sizeof(void*));
EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pSet8Static, pSet16Instance, sizeof(void*));
diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc
index 249a8b04fb..d8aa00c45e 100644
--- a/runtime/jit/jit_code_cache.cc
+++ b/runtime/jit/jit_code_cache.cc
@@ -563,7 +563,7 @@ void JitCodeCache::SweepRootTables(IsMarkedVisitor* visitor) {
}
}
-void JitCodeCache::FreeCode(const void* code_ptr) {
+void JitCodeCache::FreeCodeAndData(const void* code_ptr) {
uintptr_t allocation = FromCodeToAllocation(code_ptr);
// Notify native debugger that we are about to remove the code.
// It does nothing if we are not using native debugger.
@@ -590,7 +590,7 @@ void JitCodeCache::FreeAllMethodHeaders(
MutexLock mu(Thread::Current(), lock_);
ScopedCodeCacheWrite scc(this);
for (const OatQuickMethodHeader* method_header : method_headers) {
- FreeCode(method_header->GetCode());
+ FreeCodeAndData(method_header->GetCode());
}
}
@@ -916,7 +916,7 @@ bool JitCodeCache::RemoveMethodLocked(ArtMethod* method, bool release_memory) {
in_cache = true;
if (it->second.GetMethods().empty()) {
if (release_memory) {
- FreeCode(it->second.GetCode());
+ FreeCodeAndData(it->second.GetCode());
}
jni_stubs_map_.erase(it);
} else {
@@ -928,7 +928,7 @@ bool JitCodeCache::RemoveMethodLocked(ArtMethod* method, bool release_memory) {
if (it->second == method) {
in_cache = true;
if (release_memory) {
- FreeCode(it->first);
+ FreeCodeAndData(it->first);
}
it = method_code_map_.erase(it);
} else {
diff --git a/runtime/jit/jit_code_cache.h b/runtime/jit/jit_code_cache.h
index b10f57eff2..958e8e8aa2 100644
--- a/runtime/jit/jit_code_cache.h
+++ b/runtime/jit/jit_code_cache.h
@@ -317,8 +317,8 @@ class JitCodeCache {
REQUIRES(lock_)
REQUIRES(Locks::mutator_lock_);
- // Free in the mspace allocations for `code_ptr`.
- void FreeCode(const void* code_ptr) REQUIRES(lock_);
+ // Free code and data allocations for `code_ptr`.
+ void FreeCodeAndData(const void* code_ptr) REQUIRES(lock_);
// Number of bytes allocated in the code cache.
size_t CodeCacheSizeLocked() REQUIRES(lock_);
@@ -357,10 +357,10 @@ class JitCodeCache {
REQUIRES(lock_)
REQUIRES_SHARED(Locks::mutator_lock_);
- void FreeCode(uint8_t* code) REQUIRES(lock_);
uint8_t* AllocateCode(size_t code_size) REQUIRES(lock_);
- void FreeData(uint8_t* data) REQUIRES(lock_);
+ void FreeCode(uint8_t* code) REQUIRES(lock_);
uint8_t* AllocateData(size_t data_size) REQUIRES(lock_);
+ void FreeData(uint8_t* data) REQUIRES(lock_);
bool IsWeakAccessEnabled(Thread* self) const;
void WaitUntilInlineCacheAccessible(Thread* self)
diff --git a/runtime/oat.h b/runtime/oat.h
index 0318606f87..6c683f1541 100644
--- a/runtime/oat.h
+++ b/runtime/oat.h
@@ -32,8 +32,8 @@ class InstructionSetFeatures;
class PACKED(4) OatHeader {
public:
static constexpr uint8_t kOatMagic[] = { 'o', 'a', 't', '\n' };
- // Last oat version changed reason: Use rMR as temp in Baker RB introspection marking.
- static constexpr uint8_t kOatVersion[] = { '1', '4', '1', '\0' };
+ // Last oat version changed reason: compiler support const-method-handle
+ static constexpr uint8_t kOatVersion[] = { '1', '4', '3', '\0' };
static constexpr const char* kImageLocationKey = "image-location";
static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline";
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index 9c8b6512a7..7d69927ffb 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -1217,7 +1217,9 @@ bool OatFileAssistant::OatFileInfo::ClassLoaderContextIsOkay(ClassLoaderContext*
return false;
}
- bool result = context->VerifyClassLoaderContextMatch(file->GetClassLoaderContext());
+
+ const bool result = context->VerifyClassLoaderContextMatch(file->GetClassLoaderContext()) !=
+ ClassLoaderContext::VerificationResult::kMismatch;
if (!result) {
VLOG(oat) << "ClassLoaderContext check failed. Context was "
<< file->GetClassLoaderContext()
diff --git a/runtime/oat_file_manager.cc b/runtime/oat_file_manager.cc
index 16e6cf375c..59a1045ba2 100644
--- a/runtime/oat_file_manager.cc
+++ b/runtime/oat_file_manager.cc
@@ -276,9 +276,19 @@ static void AddNext(/*inout*/DexFileAndClassPair& original,
}
}
-static bool CollisionCheck(std::vector<const DexFile*>& dex_files_loaded,
- std::vector<const DexFile*>& dex_files_unloaded,
- std::string* error_msg /*out*/) {
+static bool CheckClassCollision(const OatFile* oat_file,
+ const ClassLoaderContext* context,
+ std::string* error_msg /*out*/) {
+ std::vector<const DexFile*> dex_files_loaded = context->FlattenOpenedDexFiles();
+
+ // Vector that holds the newly opened dex files live, this is done to prevent leaks.
+ std::vector<std::unique_ptr<const DexFile>> opened_dex_files;
+
+ ScopedTrace st("Collision check");
+ // Add dex files from the oat file to check.
+ std::vector<const DexFile*> dex_files_unloaded;
+ AddDexFilesFromOat(oat_file, &dex_files_unloaded, &opened_dex_files);
+
// Generate type index information for each dex file.
std::vector<TypeIndexInfo> loaded_types;
for (const DexFile* dex_file : dex_files_loaded) {
@@ -355,9 +365,10 @@ static bool CollisionCheck(std::vector<const DexFile*>& dex_files_loaded,
// against the following top element. If the descriptor is the same, it is now checked whether
// the two elements agree on whether their dex file was from an already-loaded oat-file or the
// new oat file. Any disagreement indicates a collision.
-bool OatFileManager::HasCollisions(const OatFile* oat_file,
- const ClassLoaderContext* context,
- std::string* error_msg /*out*/) const {
+OatFileManager::CheckCollisionResult OatFileManager::CheckCollision(
+ const OatFile* oat_file,
+ const ClassLoaderContext* context,
+ /*out*/ std::string* error_msg) const {
DCHECK(oat_file != nullptr);
DCHECK(error_msg != nullptr);
@@ -367,28 +378,59 @@ bool OatFileManager::HasCollisions(const OatFile* oat_file,
// Note that this has correctness implications as we cannot guarantee that the class resolution
// used during compilation is OK (b/37777332).
if (context == nullptr) {
- LOG(WARNING) << "Skipping duplicate class check due to unsupported classloader";
- return false;
+ LOG(WARNING) << "Skipping duplicate class check due to unsupported classloader";
+ return CheckCollisionResult::kSkippedUnsupportedClassLoader;
}
- // If the pat file loading context matches the context used during compilation then we accept
+ // If the oat file loading context matches the context used during compilation then we accept
// the oat file without addition checks
- if (context->VerifyClassLoaderContextMatch(oat_file->GetClassLoaderContext())) {
- return false;
+ ClassLoaderContext::VerificationResult result = context->VerifyClassLoaderContextMatch(
+ oat_file->GetClassLoaderContext(),
+ /*verify_names*/ true,
+ /*verify_checksums*/ true);
+ switch (result) {
+ case ClassLoaderContext::VerificationResult::kForcedToSkipChecks:
+ return CheckCollisionResult::kSkippedClassLoaderContextSharedLibrary;
+ case ClassLoaderContext::VerificationResult::kMismatch:
+ // Mismatched context, do the actual collision check.
+ break;
+ case ClassLoaderContext::VerificationResult::kVerifies:
+ return CheckCollisionResult::kNoCollisions;
}
// The class loader context does not match. Perform a full duplicate classes check.
+ return CheckClassCollision(oat_file, context, error_msg)
+ ? CheckCollisionResult::kPerformedHasCollisions : CheckCollisionResult::kNoCollisions;
+}
- std::vector<const DexFile*> dex_files_loaded = context->FlattenOpenedDexFiles();
-
- // Vector that holds the newly opened dex files live, this is done to prevent leaks.
- std::vector<std::unique_ptr<const DexFile>> opened_dex_files;
+bool OatFileManager::AcceptOatFile(CheckCollisionResult result) const {
+ // Take the file only if it has no collisions, or we must take it because of preopting.
+ // Also accept oat files for shared libraries and unsupported class loaders.
+ return result != CheckCollisionResult::kPerformedHasCollisions;
+}
- ScopedTrace st("Collision check");
- // Add dex files from the oat file to check.
- std::vector<const DexFile*> dex_files_unloaded;
- AddDexFilesFromOat(oat_file, &dex_files_unloaded, &opened_dex_files);
- return CollisionCheck(dex_files_loaded, dex_files_unloaded, error_msg);
+bool OatFileManager::ShouldLoadAppImage(CheckCollisionResult check_collision_result,
+ const OatFile* source_oat_file,
+ ClassLoaderContext* context,
+ std::string* error_msg) {
+ Runtime* const runtime = Runtime::Current();
+ if (kEnableAppImage && (!runtime->IsJavaDebuggable() || source_oat_file->IsDebuggable())) {
+ // If we verified the class loader context (skipping due to the special marker doesn't
+ // count), then also avoid the collision check.
+ bool load_image = check_collision_result == CheckCollisionResult::kNoCollisions;
+ // If we skipped the collision check, we need to reverify to be sure its OK to load the
+ // image.
+ if (!load_image &&
+ check_collision_result ==
+ CheckCollisionResult::kSkippedClassLoaderContextSharedLibrary) {
+ // We can load the app image only if there are no collisions. If we know the
+ // class loader but didn't do the full collision check in HasCollisions(),
+ // do it now. b/77342775
+ load_image = !CheckClassCollision(source_oat_file, context, error_msg);
+ }
+ return load_image;
+ }
+ return false;
}
std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat(
@@ -473,16 +515,17 @@ std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat(
<< reinterpret_cast<uintptr_t>(oat_file.get())
<< " (executable=" << (oat_file != nullptr ? oat_file->IsExecutable() : false) << ")";
+ CheckCollisionResult check_collision_result = CheckCollisionResult::kPerformedHasCollisions;
if ((class_loader != nullptr || dex_elements != nullptr) && oat_file != nullptr) {
// Prevent oat files from being loaded if no class_loader or dex_elements are provided.
// This can happen when the deprecated DexFile.<init>(String) is called directly, and it
// could load oat files without checking the classpath, which would be incorrect.
// Take the file only if it has no collisions, or we must take it because of preopting.
- bool accept_oat_file =
- !HasCollisions(oat_file.get(), context.get(), /*out*/ &error_msg);
+ check_collision_result = CheckCollision(oat_file.get(), context.get(), /*out*/ &error_msg);
+ bool accept_oat_file = AcceptOatFile(check_collision_result);
if (!accept_oat_file) {
// Failed the collision check. Print warning.
- if (Runtime::Current()->IsDexFileFallbackEnabled()) {
+ if (runtime->IsDexFileFallbackEnabled()) {
if (!oat_file_assistant.HasOriginalDexFiles()) {
// We need to fallback but don't have original dex files. We have to
// fallback to opening the existing oat file. This is potentially
@@ -529,10 +572,11 @@ std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat(
// We need to throw away the image space if we are debuggable but the oat-file source of the
// image is not otherwise we might get classes with inlined methods or other such things.
std::unique_ptr<gc::space::ImageSpace> image_space;
- if (kEnableAppImage && (!runtime->IsJavaDebuggable() || source_oat_file->IsDebuggable())) {
+ if (ShouldLoadAppImage(check_collision_result,
+ source_oat_file,
+ context.get(),
+ &error_msg)) {
image_space = oat_file_assistant.OpenImageSpace(source_oat_file);
- } else {
- image_space = nullptr;
}
if (image_space != nullptr) {
ScopedObjectAccess soa(self);
diff --git a/runtime/oat_file_manager.h b/runtime/oat_file_manager.h
index 038474e31f..80456e9b75 100644
--- a/runtime/oat_file_manager.h
+++ b/runtime/oat_file_manager.h
@@ -108,23 +108,39 @@ class OatFileManager {
void SetOnlyUseSystemOatFiles();
private:
+ enum class CheckCollisionResult {
+ kSkippedUnsupportedClassLoader,
+ kSkippedClassLoaderContextSharedLibrary,
+ kNoCollisions,
+ kPerformedHasCollisions,
+ };
+
// Check that the class loader context of the given oat file matches the given context.
// This will perform a check that all class loaders in the chain have the same type and
// classpath.
// If the context is null (which means the initial class loader was null or unsupported)
- // this returns false.
+ // this returns kSkippedUnsupportedClassLoader.
// If the context does not validate the method will check for duplicate class definitions of
// the given oat file against the oat files (either from the class loaders if possible or all
// non-boot oat files otherwise).
- // Return true if there are any class definition collisions in the oat_file.
- bool HasCollisions(const OatFile* oat_file,
- const ClassLoaderContext* context,
- /*out*/ std::string* error_msg) const
+ // Return kPerformedHasCollisions if there are any class definition collisions in the oat_file.
+ CheckCollisionResult CheckCollision(const OatFile* oat_file,
+ const ClassLoaderContext* context,
+ /*out*/ std::string* error_msg) const
REQUIRES(!Locks::oat_file_manager_lock_);
const OatFile* FindOpenedOatFileFromOatLocationLocked(const std::string& oat_location) const
REQUIRES(Locks::oat_file_manager_lock_);
+ // Return true if we should accept the oat file.
+ bool AcceptOatFile(CheckCollisionResult result) const;
+
+ // Return true if we should attempt to load the app image.
+ bool ShouldLoadAppImage(CheckCollisionResult check_collision_result,
+ const OatFile* source_oat_file,
+ ClassLoaderContext* context,
+ std::string* error_msg);
+
std::set<std::unique_ptr<const OatFile>> oat_files_ GUARDED_BY(Locks::oat_file_manager_lock_);
bool have_non_pic_oat_file_;
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index bc29aaca6d..3518d2facd 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -2287,14 +2287,10 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
case Instruction::CONST_METHOD_HANDLE:
work_line_->SetRegisterType<LockOp::kClear>(
this, inst->VRegA_21c(), reg_types_.JavaLangInvokeMethodHandle());
- // TODO: add compiler support for const-method-{handle,type} (b/66890674)
- Fail(VERIFY_ERROR_FORCE_INTERPRETER);
break;
case Instruction::CONST_METHOD_TYPE:
work_line_->SetRegisterType<LockOp::kClear>(
this, inst->VRegA_21c(), reg_types_.JavaLangInvokeMethodType());
- // TODO: add compiler support for const-method-{handle,type} (b/66890674)
- Fail(VERIFY_ERROR_FORCE_INTERPRETER);
break;
case Instruction::MONITOR_ENTER:
work_line_->PushMonitor(this, inst->VRegA_11x(), work_insn_idx_);
diff --git a/test/172-app-image-twice/check b/test/172-app-image-twice/check
new file mode 100755
index 0000000000..26a97a48ae
--- /dev/null
+++ b/test/172-app-image-twice/check
@@ -0,0 +1,18 @@
+#!/bin/bash
+#
+# Copyright (C) 2018 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.
+
+# Remove all lines not containing "passed".
+grep "^passed" "$2" | diff --strip-trailing-cr -q "$1" - >/dev/null
diff --git a/test/172-app-image-twice/debug_print_class.cc b/test/172-app-image-twice/debug_print_class.cc
new file mode 100644
index 0000000000..6c3de20f2d
--- /dev/null
+++ b/test/172-app-image-twice/debug_print_class.cc
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2018 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 "debug_print.h"
+#include "dex/dex_file.h"
+#include "mirror/class-inl.h"
+#include "scoped_thread_state_change-inl.h"
+#include "thread-current-inl.h"
+
+namespace art {
+
+extern "C" JNIEXPORT void JNICALL Java_Main_debugPrintClass(JNIEnv*, jclass, jclass cls) {
+ ScopedObjectAccess soa(Thread::Current());
+ ObjPtr<mirror::Class> klass = soa.Decode<mirror::Class>(cls);
+ LOG(ERROR) << "klass: " << klass.Ptr() << " dex_file: " << klass->GetDexFile().GetLocation()
+ << "/" << static_cast<const void*>(&klass->GetDexFile())
+ << " " << DescribeSpace(klass);
+}
+
+} // namespace art
diff --git a/test/172-app-image-twice/expected.txt b/test/172-app-image-twice/expected.txt
new file mode 100644
index 0000000000..b0aad4deb5
--- /dev/null
+++ b/test/172-app-image-twice/expected.txt
@@ -0,0 +1 @@
+passed
diff --git a/test/172-app-image-twice/info.txt b/test/172-app-image-twice/info.txt
new file mode 100644
index 0000000000..028046e872
--- /dev/null
+++ b/test/172-app-image-twice/info.txt
@@ -0,0 +1 @@
+Regression test for loading the same app image twice.
diff --git a/test/172-app-image-twice/profile b/test/172-app-image-twice/profile
new file mode 100644
index 0000000000..70cb2efbb5
--- /dev/null
+++ b/test/172-app-image-twice/profile
@@ -0,0 +1 @@
+LTestClass;
diff --git a/test/172-app-image-twice/run b/test/172-app-image-twice/run
new file mode 100644
index 0000000000..aa2819075f
--- /dev/null
+++ b/test/172-app-image-twice/run
@@ -0,0 +1,28 @@
+#!/bin/bash
+#
+# Copyright (C) 2018 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.
+
+# Build an app image with TestClass (specified by profile) and class loader
+# context that skips the duplicate class checks.
+
+# Target and host use a different shell, and we need to special case the
+# passing of the class loader context marker.
+if [[ "$@" = *" --host "* ]]; then
+ ${RUN} $@ --profile -Xcompiler-option --compiler-filter=speed-profile \
+ -Xcompiler-option --class-loader-context=\&
+else
+ ${RUN} $@ --profile -Xcompiler-option --compiler-filter=speed-profile \
+ -Xcompiler-option '--class-loader-context=\&'
+fi
diff --git a/test/172-app-image-twice/src/Main.java b/test/172-app-image-twice/src/Main.java
new file mode 100644
index 0000000000..a1c151a6bc
--- /dev/null
+++ b/test/172-app-image-twice/src/Main.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2018 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.lang.reflect.Method;
+
+public class Main {
+ private static String TEST_NAME = "172-app-image-twice";
+
+ public static void main(String args[]) throws Exception {
+ System.loadLibrary(args[0]);
+
+ Class<?> tc1 = Class.forName("TestClass");
+
+ String dexPath = System.getenv("DEX_LOCATION") + "/" + TEST_NAME + ".jar";
+ Class<?> bdcl = Class.forName("dalvik.system.BaseDexClassLoader");
+ Method addDexPathMethod = bdcl.getDeclaredMethod("addDexPath", String.class);
+ addDexPathMethod.invoke(Main.class.getClassLoader(), dexPath);
+
+ Class<?> tc2 = Class.forName("TestClass");
+
+ // Add extra logging to simulate libcore logging, this logging should not be compared
+ // against.
+ System.out.println("Extra logging");
+
+ if (tc1 != tc2) {
+ System.out.println("Class mismatch!");
+ debugPrintClass(tc1);
+ debugPrintClass(tc2);
+ } else {
+ System.out.println("passed");
+ }
+ }
+
+ public static native void debugPrintClass(Class<?> cls);
+}
diff --git a/test/172-app-image-twice/src/TestClass.java b/test/172-app-image-twice/src/TestClass.java
new file mode 100644
index 0000000000..5381718f6e
--- /dev/null
+++ b/test/172-app-image-twice/src/TestClass.java
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class TestClass {
+}
diff --git a/test/979-const-method-handle/expected.txt b/test/979-const-method-handle/expected.txt
index bc943e368e..bbaaedb0af 100644
--- a/test/979-const-method-handle/expected.txt
+++ b/test/979-const-method-handle/expected.txt
@@ -1,6 +1,9 @@
(int,Integer,System)String
+repeatConstMethodType0((int,Integer,System)String)
+repeatConstMethodType1((LocalClass)void)
Hello World! And Hello Zog
Hello World! And Hello Zorba
name is HoverFly
2.718281828459045
+repeatConstMethodHandle()
Attempting to set Math.E raised IAE
diff --git a/test/979-const-method-handle/src/Main.java b/test/979-const-method-handle/src/Main.java
index 663814f232..427ca7a306 100644
--- a/test/979-const-method-handle/src/Main.java
+++ b/test/979-const-method-handle/src/Main.java
@@ -20,78 +20,146 @@ import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
class Main {
+ /**
+ * Number of iterations run to attempt to trigger JIT compilation. These tests run on ART and
+ * the RI so they iterate rather than using the ART only native method ensureJitCompiled().
+ */
+ private static final int ITERATIONS_FOR_JIT = 12000;
+
+ /** A static field updated by method handle getters and setters. */
private static String name = "default";
private static void unreachable() {
throw new Error("Unreachable");
}
+ private static void assertEquals(Object expected, Object actual) {
+ if (!expected.equals(actual)) {
+ throw new AssertionError("Assertion failure: " + expected + " != " + actual);
+ }
+ }
+
+ private static class LocalClass {
+ public LocalClass() {}
+
+ private int field;
+ }
+
@ConstantMethodType(
- returnType = String.class,
- parameterTypes = {int.class, Integer.class, System.class}
- )
+ returnType = String.class,
+ parameterTypes = {int.class, Integer.class, System.class})
private static MethodType methodType0() {
unreachable();
return null;
}
+ @ConstantMethodType(
+ returnType = void.class,
+ parameterTypes = {LocalClass.class})
+ private static MethodType methodType1() {
+ unreachable();
+ return null;
+ }
+
+ private static void repeatConstMethodType0(MethodType expected) {
+ System.out.print("repeatConstMethodType0(");
+ System.out.print(expected);
+ System.out.println(")");
+ for (int i = 0; i < ITERATIONS_FOR_JIT; ++i) {
+ MethodType actual = methodType0();
+ assertEquals(expected, actual);
+ }
+ }
+
+ private static void repeatConstMethodType1(MethodType expected) {
+ System.out.print("repeatConstMethodType1(");
+ System.out.print(expected);
+ System.out.println(")");
+ for (int i = 0; i < ITERATIONS_FOR_JIT; ++i) {
+ MethodType actual = methodType1();
+ assertEquals(expected, actual);
+ }
+ }
+
static void helloWorld(String who) {
System.out.print("Hello World! And Hello ");
System.out.println(who);
}
@ConstantMethodHandle(
- kind = ConstantMethodHandle.INVOKE_STATIC,
- owner = "Main",
- fieldOrMethodName = "helloWorld",
- descriptor = "(Ljava/lang/String;)V"
- )
+ kind = ConstantMethodHandle.INVOKE_STATIC,
+ owner = "Main",
+ fieldOrMethodName = "helloWorld",
+ descriptor = "(Ljava/lang/String;)V")
private static MethodHandle printHelloHandle() {
unreachable();
return null;
}
@ConstantMethodHandle(
- kind = ConstantMethodHandle.STATIC_PUT,
- owner = "Main",
- fieldOrMethodName = "name",
- descriptor = "Ljava/lang/String;"
- )
+ kind = ConstantMethodHandle.STATIC_PUT,
+ owner = "Main",
+ fieldOrMethodName = "name",
+ descriptor = "Ljava/lang/String;")
private static MethodHandle setNameHandle() {
unreachable();
return null;
}
@ConstantMethodHandle(
- kind = ConstantMethodHandle.STATIC_GET,
- owner = "java/lang/Math",
- fieldOrMethodName = "E",
- descriptor = "D"
- )
+ kind = ConstantMethodHandle.STATIC_GET,
+ owner = "Main",
+ fieldOrMethodName = "name",
+ descriptor = "Ljava/lang/String;")
+ private static MethodHandle getNameHandle() {
+ unreachable();
+ return null;
+ }
+
+ @ConstantMethodHandle(
+ kind = ConstantMethodHandle.STATIC_GET,
+ owner = "java/lang/Math",
+ fieldOrMethodName = "E",
+ descriptor = "D")
private static MethodHandle getMathE() {
unreachable();
return null;
}
@ConstantMethodHandle(
- kind = ConstantMethodHandle.STATIC_PUT,
- owner = "java/lang/Math",
- fieldOrMethodName = "E",
- descriptor = "D"
- )
+ kind = ConstantMethodHandle.STATIC_PUT,
+ owner = "java/lang/Math",
+ fieldOrMethodName = "E",
+ descriptor = "D")
private static MethodHandle putMathE() {
unreachable();
return null;
}
+ private static void repeatConstMethodHandle() throws Throwable {
+ System.out.println("repeatConstMethodHandle()");
+ String[] values = {"A", "B", "C"};
+ for (int i = 0; i < ITERATIONS_FOR_JIT; ++i) {
+ String value = values[i % values.length];
+ setNameHandle().invoke(value);
+ String actual = (String) getNameHandle().invokeExact();
+ assertEquals(value, actual);
+ assertEquals(value, name);
+ }
+ }
+
public static void main(String[] args) throws Throwable {
System.out.println(methodType0());
+ repeatConstMethodType0(
+ MethodType.methodType(String.class, int.class, Integer.class, System.class));
+ repeatConstMethodType1(MethodType.methodType(void.class, LocalClass.class));
printHelloHandle().invokeExact("Zog");
printHelloHandle().invokeExact("Zorba");
setNameHandle().invokeExact("HoverFly");
System.out.print("name is ");
System.out.println(name);
System.out.println(getMathE().invoke());
+ repeatConstMethodHandle();
try {
putMathE().invokeExact(Math.PI);
unreachable();
diff --git a/test/Android.bp b/test/Android.bp
index 0c6b449877..76189f62a9 100644
--- a/test/Android.bp
+++ b/test/Android.bp
@@ -423,6 +423,7 @@ cc_defaults {
"154-gc-loop/heap_interface.cc",
"167-visit-locks/visit_locks.cc",
"169-threadgroup-jni/jni_daemon_thread.cc",
+ "172-app-image-twice/debug_print_class.cc",
"1945-proxy-method-arguments/get_args.cc",
"203-multi-checkpoint/multi_checkpoint.cc",
"305-other-fault-handler/fault_handler.cc",
diff --git a/test/knownfailures.json b/test/knownfailures.json
index f3137587f6..f473a99a27 100644
--- a/test/knownfailures.json
+++ b/test/knownfailures.json
@@ -734,6 +734,7 @@
"164-resolution-trampoline-dex-cache",
"167-visit-locks",
"168-vmstack-annotated",
+ "172-app-image-twice",
"201-built-in-except-detail-messages",
"203-multi-checkpoint",
"304-method-tracing",
diff --git a/tools/veridex/flow_analysis.cc b/tools/veridex/flow_analysis.cc
index e2833bf01d..154c60f6ac 100644
--- a/tools/veridex/flow_analysis.cc
+++ b/tools/veridex/flow_analysis.cc
@@ -112,7 +112,12 @@ void VeriFlowAnalysis::UpdateRegister(uint32_t dex_register, const VeriClass* cl
RegisterValue(RegisterSource::kNone, DexFileReference(nullptr, 0), cls);
}
-const RegisterValue& VeriFlowAnalysis::GetRegister(uint32_t dex_register) {
+void VeriFlowAnalysis::UpdateRegister(uint32_t dex_register, int32_t value, const VeriClass* cls) {
+ current_registers_[dex_register] =
+ RegisterValue(RegisterSource::kConstant, value, DexFileReference(nullptr, 0), cls);
+}
+
+const RegisterValue& VeriFlowAnalysis::GetRegister(uint32_t dex_register) const {
return current_registers_[dex_register];
}
@@ -131,6 +136,49 @@ RegisterValue VeriFlowAnalysis::GetFieldType(uint32_t field_index) {
return RegisterValue(RegisterSource::kField, DexFileReference(&dex_file, field_index), cls);
}
+int VeriFlowAnalysis::GetBranchFlags(const Instruction& instruction) const {
+ switch (instruction.Opcode()) {
+ #define IF_XX(cond, op) \
+ case Instruction::IF_##cond: { \
+ RegisterValue lhs = GetRegister(instruction.VRegA()); \
+ RegisterValue rhs = GetRegister(instruction.VRegB()); \
+ if (lhs.IsConstant() && rhs.IsConstant()) { \
+ if (lhs.GetConstant() op rhs.GetConstant()) { \
+ return Instruction::kBranch; \
+ } else { \
+ return Instruction::kContinue; \
+ } \
+ } \
+ break; \
+ } \
+ case Instruction::IF_##cond##Z: { \
+ RegisterValue val = GetRegister(instruction.VRegA()); \
+ if (val.IsConstant()) { \
+ if (val.GetConstant() op 0) { \
+ return Instruction::kBranch; \
+ } else { \
+ return Instruction::kContinue; \
+ } \
+ } \
+ break; \
+ }
+
+ IF_XX(EQ, ==);
+ IF_XX(NE, !=);
+ IF_XX(LT, <);
+ IF_XX(LE, <=);
+ IF_XX(GT, >);
+ IF_XX(GE, >=);
+
+ #undef IF_XX
+
+ default:
+ break;
+ }
+
+ return Instruction::FlagsOf(instruction.Opcode());
+}
+
void VeriFlowAnalysis::AnalyzeCode() {
std::vector<uint32_t> work_list;
work_list.push_back(0);
@@ -149,16 +197,17 @@ void VeriFlowAnalysis::AnalyzeCode() {
ProcessDexInstruction(inst);
SetVisited(dex_pc);
- int opcode_flags = Instruction::FlagsOf(inst.Opcode());
- if ((opcode_flags & Instruction::kContinue) != 0) {
- if ((opcode_flags & Instruction::kBranch) != 0) {
+ int branch_flags = GetBranchFlags(inst);
+
+ if ((branch_flags & Instruction::kContinue) != 0) {
+ if ((branch_flags & Instruction::kBranch) != 0) {
uint32_t branch_dex_pc = dex_pc + inst.GetTargetOffset();
if (MergeRegisterValues(branch_dex_pc)) {
work_list.push_back(branch_dex_pc);
}
}
dex_pc += inst.SizeInCodeUnits();
- } else if ((opcode_flags & Instruction::kBranch) != 0) {
+ } else if ((branch_flags & Instruction::kBranch) != 0) {
dex_pc += inst.GetTargetOffset();
DCHECK(IsBranchTarget(dex_pc));
} else {
@@ -178,12 +227,30 @@ void VeriFlowAnalysis::AnalyzeCode() {
void VeriFlowAnalysis::ProcessDexInstruction(const Instruction& instruction) {
switch (instruction.Opcode()) {
- case Instruction::CONST_4:
- case Instruction::CONST_16:
- case Instruction::CONST:
+ case Instruction::CONST_4: {
+ int32_t register_index = instruction.VRegA();
+ int32_t value = instruction.VRegB_11n();
+ UpdateRegister(register_index, value, VeriClass::integer_);
+ break;
+ }
+ case Instruction::CONST_16: {
+ int32_t register_index = instruction.VRegA();
+ int32_t value = instruction.VRegB_21s();
+ UpdateRegister(register_index, value, VeriClass::integer_);
+ break;
+ }
+
+ case Instruction::CONST: {
+ int32_t register_index = instruction.VRegA();
+ int32_t value = instruction.VRegB_31i();
+ UpdateRegister(register_index, value, VeriClass::integer_);
+ break;
+ }
+
case Instruction::CONST_HIGH16: {
int32_t register_index = instruction.VRegA();
- UpdateRegister(register_index, VeriClass::integer_);
+ int32_t value = instruction.VRegB_21h();
+ UpdateRegister(register_index, value, VeriClass::integer_);
break;
}
@@ -268,6 +335,8 @@ void VeriFlowAnalysis::ProcessDexInstruction(const Instruction& instruction) {
case Instruction::RETURN: {
break;
}
+
+ // If operations will be handled when looking at the control flow.
#define IF_XX(cond) \
case Instruction::IF_##cond: break; \
case Instruction::IF_##cond##Z: break
@@ -279,6 +348,8 @@ void VeriFlowAnalysis::ProcessDexInstruction(const Instruction& instruction) {
IF_XX(GT);
IF_XX(GE);
+ #undef IF_XX
+
case Instruction::GOTO:
case Instruction::GOTO_16:
case Instruction::GOTO_32: {
@@ -495,7 +566,13 @@ void VeriFlowAnalysis::ProcessDexInstruction(const Instruction& instruction) {
case Instruction::SGET_BYTE:
case Instruction::SGET_CHAR:
case Instruction::SGET_SHORT: {
- UpdateRegister(instruction.VRegA_22c(), GetFieldType(instruction.VRegC_22c()));
+ uint32_t dest_reg = instruction.VRegA_21c();
+ uint16_t field_index = instruction.VRegB_21c();
+ if (VeriClass::sdkInt_ != nullptr && resolver_->GetField(field_index) == VeriClass::sdkInt_) {
+ UpdateRegister(dest_reg, gTargetSdkVersion, VeriClass::integer_);
+ } else {
+ UpdateRegister(dest_reg, GetFieldType(instruction.VRegC_22c()));
+ }
break;
}
diff --git a/tools/veridex/flow_analysis.h b/tools/veridex/flow_analysis.h
index 62c9916a61..fc093600c3 100644
--- a/tools/veridex/flow_analysis.h
+++ b/tools/veridex/flow_analysis.h
@@ -35,6 +35,7 @@ enum class RegisterSource {
kMethod,
kClass,
kString,
+ kConstant,
kNone
};
@@ -44,28 +45,33 @@ enum class RegisterSource {
class RegisterValue {
public:
RegisterValue() : source_(RegisterSource::kNone),
- parameter_index_(0),
+ value_(0),
reference_(nullptr, 0),
type_(nullptr) {}
RegisterValue(RegisterSource source, DexFileReference reference, const VeriClass* type)
- : source_(source), parameter_index_(0), reference_(reference), type_(type) {}
+ : source_(source), value_(0), reference_(reference), type_(type) {}
RegisterValue(RegisterSource source,
- uint32_t parameter_index,
+ uint32_t value,
DexFileReference reference,
const VeriClass* type)
- : source_(source), parameter_index_(parameter_index), reference_(reference), type_(type) {}
+ : source_(source), value_(value), reference_(reference), type_(type) {}
RegisterSource GetSource() const { return source_; }
DexFileReference GetDexFileReference() const { return reference_; }
const VeriClass* GetType() const { return type_; }
uint32_t GetParameterIndex() const {
CHECK(IsParameter());
- return parameter_index_;
+ return value_;
+ }
+ uint32_t GetConstant() const {
+ CHECK(IsConstant());
+ return value_;
}
bool IsParameter() const { return source_ == RegisterSource::kParameter; }
bool IsClass() const { return source_ == RegisterSource::kClass; }
bool IsString() const { return source_ == RegisterSource::kString; }
+ bool IsConstant() const { return source_ == RegisterSource::kConstant; }
std::string ToString() const {
switch (source_) {
@@ -91,7 +97,7 @@ class RegisterValue {
private:
RegisterSource source_;
- uint32_t parameter_index_;
+ uint32_t value_;
DexFileReference reference_;
const VeriClass* type_;
};
@@ -137,12 +143,15 @@ class VeriFlowAnalysis {
uint32_t dex_register, RegisterSource kind, VeriClass* cls, uint32_t source_id);
void UpdateRegister(uint32_t dex_register, const RegisterValue& value);
void UpdateRegister(uint32_t dex_register, const VeriClass* cls);
+ void UpdateRegister(uint32_t dex_register, int32_t value, const VeriClass* cls);
void ProcessDexInstruction(const Instruction& inst);
void SetVisited(uint32_t dex_pc);
RegisterValue GetFieldType(uint32_t field_index);
+ int GetBranchFlags(const Instruction& instruction) const;
+
protected:
- const RegisterValue& GetRegister(uint32_t dex_register);
+ const RegisterValue& GetRegister(uint32_t dex_register) const;
RegisterValue GetReturnType(uint32_t method_index);
VeridexResolver* resolver_;
diff --git a/tools/veridex/veridex.cc b/tools/veridex/veridex.cc
index dc7ea94032..bcd4815a38 100644
--- a/tools/veridex/veridex.cc
+++ b/tools/veridex/veridex.cc
@@ -25,6 +25,7 @@
#include "precise_hidden_api_finder.h"
#include "resolver.h"
+#include <cstdlib>
#include <sstream>
namespace art {
@@ -62,6 +63,7 @@ VeriMethod VeriClass::getMethod_ = nullptr;
VeriMethod VeriClass::getDeclaredMethod_ = nullptr;
VeriMethod VeriClass::getClass_ = nullptr;
VeriMethod VeriClass::loadClass_ = nullptr;
+VeriField VeriClass::sdkInt_ = nullptr;
struct VeridexOptions {
const char* dex_file = nullptr;
@@ -70,6 +72,7 @@ struct VeridexOptions {
const char* light_greylist = nullptr;
const char* dark_greylist = nullptr;
bool precise = true;
+ int target_sdk_version = 28; /* P */
};
static const char* Substr(const char* str, int index) {
@@ -91,6 +94,7 @@ static void ParseArgs(VeridexOptions* options, int argc, char** argv) {
static const char* kDarkGreylistOption = "--dark-greylist=";
static const char* kLightGreylistOption = "--light-greylist=";
static const char* kImprecise = "--imprecise";
+ static const char* kTargetSdkVersion = "--target-sdk-version=";
for (int i = 0; i < argc; ++i) {
if (StartsWith(argv[i], kDexFileOption)) {
@@ -105,6 +109,8 @@ static void ParseArgs(VeridexOptions* options, int argc, char** argv) {
options->light_greylist = Substr(argv[i], strlen(kLightGreylistOption));
} else if (strcmp(argv[i], kImprecise) == 0) {
options->precise = false;
+ } else if (StartsWith(argv[i], kTargetSdkVersion)) {
+ options->target_sdk_version = atoi(Substr(argv[i], strlen(kTargetSdkVersion)));
}
}
}
@@ -124,6 +130,7 @@ class Veridex {
static int Run(int argc, char** argv) {
VeridexOptions options;
ParseArgs(&options, argc, argv);
+ gTargetSdkVersion = options.target_sdk_version;
std::vector<std::string> boot_content;
std::vector<std::string> app_content;
@@ -200,6 +207,11 @@ class Veridex {
VeriClass::loadClass_ = boot_resolvers[0]->LookupDeclaredMethodIn(
*VeriClass::class_loader_, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
+ VeriClass* version = type_map["Landroid/os/Build$VERSION;"];
+ if (version != nullptr) {
+ VeriClass::sdkInt_ = boot_resolvers[0]->LookupFieldIn(*version, "SDK_INT", "I");
+ }
+
std::vector<std::unique_ptr<VeridexResolver>> app_resolvers;
Resolve(app_dex_files, resolver_map, type_map, &app_resolvers);
diff --git a/tools/veridex/veridex.h b/tools/veridex/veridex.h
index 9c0a158174..31ddbf439e 100644
--- a/tools/veridex/veridex.h
+++ b/tools/veridex/veridex.h
@@ -24,6 +24,8 @@
namespace art {
+static int gTargetSdkVersion = 1000; // Will be initialized after parsing options.
+
/**
* Abstraction for fields defined in dex files. Currently, that's a pointer into their
* `encoded_field` description.
@@ -86,6 +88,8 @@ class VeriClass {
static VeriMethod getClass_;
static VeriMethod loadClass_;
+ static VeriField sdkInt_;
+
private:
Primitive::Type kind_;
uint8_t dimensions_;