summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build/Android.common_build.mk6
-rw-r--r--build/Android.gtest.mk3
-rw-r--r--build/Android.oat.mk4
-rw-r--r--compiler/dex/type_inference_test.cc2
-rw-r--r--compiler/driver/compiler_driver.cc6
-rw-r--r--compiler/driver/compiler_driver_test.cc9
-rw-r--r--compiler/jni/jni_compiler_test.cc6
-rw-r--r--compiler/oat_test.cc5
-rw-r--r--compiler/oat_writer.cc2
-rw-r--r--compiler/optimizing/builder.h4
-rw-r--r--compiler/optimizing/gvn_test.cc8
-rw-r--r--compiler/optimizing/licm_test.cc4
-rw-r--r--compiler/optimizing/load_store_elimination.cc60
-rw-r--r--compiler/optimizing/register_allocator_test.cc4
-rw-r--r--oatdump/oatdump.cc4
-rw-r--r--runtime/base/mutex.h6
-rw-r--r--runtime/class_linker-inl.h2
-rw-r--r--runtime/class_linker.cc17
-rw-r--r--runtime/class_linker_test.cc4
-rw-r--r--runtime/dex_file.cc30
-rw-r--r--runtime/gc/collector/semi_space.cc46
-rw-r--r--runtime/gc/reference_queue_test.cc6
-rw-r--r--runtime/handle.h10
-rw-r--r--runtime/interpreter/unstarted_runtime.cc11
-rw-r--r--runtime/java_vm_ext.cc9
-rw-r--r--runtime/java_vm_ext.h5
-rw-r--r--runtime/jit/jit.cc18
-rw-r--r--runtime/jit/jit.h1
-rw-r--r--runtime/jit/jit_code_cache.cc5
-rw-r--r--runtime/jit/jit_code_cache.h5
-rw-r--r--runtime/jit/offline_profiling_info.cc45
-rw-r--r--runtime/jit/offline_profiling_info.h4
-rw-r--r--runtime/native/dalvik_system_VMRuntime.cc28
-rw-r--r--runtime/native/java_lang_Class.cc3
-rw-r--r--runtime/native/java_lang_Runtime.cc16
-rw-r--r--runtime/runtime.cc11
-rw-r--r--runtime/runtime.h3
-rw-r--r--runtime/well_known_classes.cc2
-rw-r--r--test/530-checker-lse/src/Main.java39
39 files changed, 282 insertions, 171 deletions
diff --git a/build/Android.common_build.mk b/build/Android.common_build.mk
index 43e1457a50..eec471e457 100644
--- a/build/Android.common_build.mk
+++ b/build/Android.common_build.mk
@@ -359,12 +359,6 @@ ART_HOST_CFLAGS += $(art_cflags) -DART_BASE_ADDRESS=$(LIBART_IMG_HOST_BASE_ADDRE
ART_HOST_CFLAGS += -DART_DEFAULT_INSTRUCTION_SET_FEATURES=default $(art_host_cflags)
ART_HOST_ASFLAGS += $(art_asflags)
-# The latest clang update trips over many of the files in art and never finishes
-# compiling for aarch64 with -O3 (or -O2). Drop back to -O1 while we investigate
-# to stop punishing the build server.
-# Bug: http://b/23256622
-ART_TARGET_CLANG_CFLAGS_arm64 += -O1
-
ifndef LIBART_IMG_TARGET_BASE_ADDRESS
$(error LIBART_IMG_TARGET_BASE_ADDRESS unset)
endif
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index 291a69de10..1c2392957f 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -564,6 +564,9 @@ define define-art-gtest
LOCAL_MODULE_PATH_64 := $$(ART_TARGET_NATIVETEST_OUT)/$$(ART_TARGET_ARCH_64)
LOCAL_MULTILIB := both
LOCAL_CLANG_CFLAGS += -Wno-used-but-marked-unused -Wno-deprecated -Wno-missing-noreturn # gtest issue
+ # clang fails to compile art/runtime/arch/stub_test.cc for arm64 without -O1
+ # b/26275713
+ LOCAL_CLANG_CFLAGS_arm64 += -O1
include $$(BUILD_EXECUTABLE)
library_path :=
2nd_library_path :=
diff --git a/build/Android.oat.mk b/build/Android.oat.mk
index 592843e0bd..50600ef903 100644
--- a/build/Android.oat.mk
+++ b/build/Android.oat.mk
@@ -112,7 +112,7 @@ $$(core_image_name): PRIVATE_CORE_COMPILE_OPTIONS := $$(core_compile_options)
$$(core_image_name): PRIVATE_CORE_IMG_NAME := $$(core_image_name)
$$(core_image_name): PRIVATE_CORE_OAT_NAME := $$(core_oat_name)
$$(core_image_name): $$(HOST_CORE_DEX_LOCATIONS) $$(core_dex2oat_dependency)
- @echo "host dex2oat: $$@ ($$?)"
+ @echo "host dex2oat: $$@"
@mkdir -p $$(dir $$@)
$$(hide) $(4) $$(DEX2OAT)$(5) --runtime-arg -Xms$(DEX2OAT_IMAGE_XMS) \
--runtime-arg -Xmx$(DEX2OAT_IMAGE_XMX) \
@@ -238,7 +238,7 @@ $$(core_image_name): PRIVATE_CORE_COMPILE_OPTIONS := $$(core_compile_options)
$$(core_image_name): PRIVATE_CORE_IMG_NAME := $$(core_image_name)
$$(core_image_name): PRIVATE_CORE_OAT_NAME := $$(core_oat_name)
$$(core_image_name): $$(TARGET_CORE_DEX_FILES) $$(core_dex2oat_dependency)
- @echo "target dex2oat: $$@ ($$?)"
+ @echo "target dex2oat: $$@"
@mkdir -p $$(dir $$@)
$$(hide) $(4) $$(DEX2OAT)$(5) --runtime-arg -Xms$(DEX2OAT_IMAGE_XMS) \
--runtime-arg -Xmx$(DEX2OAT_IMAGE_XMX) \
diff --git a/compiler/dex/type_inference_test.cc b/compiler/dex/type_inference_test.cc
index 528a18cc99..e2c0d32f97 100644
--- a/compiler/dex/type_inference_test.cc
+++ b/compiler/dex/type_inference_test.cc
@@ -253,7 +253,7 @@ class TypeInferenceTest : public testing::Test {
&cu_, cu_.class_loader, cu_.class_linker, *cu_.dex_file, nullptr /* code_item not used */,
0u /* class_def_idx not used */, 0u /* method_index not used */,
cu_.access_flags, nullptr /* verified_method not used */,
- NullHandle<mirror::DexCache>()));
+ ScopedNullHandle<mirror::DexCache>()));
cu_.mir_graph->current_method_ = 0u;
code_item_ = static_cast<DexFile::CodeItem*>(
cu_.arena.Alloc(sizeof(DexFile::CodeItem), kArenaAllocMisc));
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 56839f85f9..5630b08054 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -898,8 +898,10 @@ void CompilerDriver::LoadImageClasses(TimingLogger* timings) {
*dex_file,
Runtime::Current()->GetLinearAlloc())));
Handle<mirror::Class> klass(hs2.NewHandle(
- class_linker->ResolveType(*dex_file, exception_type_idx, dex_cache,
- NullHandle<mirror::ClassLoader>())));
+ class_linker->ResolveType(*dex_file,
+ exception_type_idx,
+ dex_cache,
+ ScopedNullHandle<mirror::ClassLoader>())));
if (klass.Get() == nullptr) {
const DexFile::TypeId& type_id = dex_file->GetTypeId(exception_type_idx);
const char* descriptor = dex_file->GetTypeDescriptor(type_id);
diff --git a/compiler/driver/compiler_driver_test.cc b/compiler/driver/compiler_driver_test.cc
index 86f8b823cc..b6abc6e8de 100644
--- a/compiler/driver/compiler_driver_test.cc
+++ b/compiler/driver/compiler_driver_test.cc
@@ -149,9 +149,14 @@ TEST_F(CompilerDriverTest, AbstractMethodErrorStub) {
jobject class_loader;
{
ScopedObjectAccess soa(Thread::Current());
- CompileVirtualMethod(NullHandle<mirror::ClassLoader>(), "java.lang.Class", "isFinalizable",
+ CompileVirtualMethod(ScopedNullHandle<mirror::ClassLoader>(),
+ "java.lang.Class",
+ "isFinalizable",
"()Z");
- CompileDirectMethod(NullHandle<mirror::ClassLoader>(), "java.lang.Object", "<init>", "()V");
+ CompileDirectMethod(ScopedNullHandle<mirror::ClassLoader>(),
+ "java.lang.Object",
+ "<init>",
+ "()V");
class_loader = LoadDex("AbstractMethod");
}
ASSERT_TRUE(class_loader != nullptr);
diff --git a/compiler/jni/jni_compiler_test.cc b/compiler/jni/jni_compiler_test.cc
index 5ab55e0614..8d60be20ee 100644
--- a/compiler/jni/jni_compiler_test.cc
+++ b/compiler/jni/jni_compiler_test.cc
@@ -220,7 +220,8 @@ void JniCompilerTest::CompileAndRunIntMethodThroughStubImpl() {
std::string reason;
ASSERT_TRUE(Runtime::Current()->GetJavaVM()->
- LoadNativeLibrary(env_, "", class_loader_, nullptr, nullptr, &reason))
+ LoadNativeLibrary(env_, "", class_loader_, /* is_shared_namespace */ false,
+ nullptr, nullptr, &reason))
<< reason;
jint result = env_->CallNonvirtualIntMethod(jobj_, jklass_, jmethod_, 24);
@@ -235,7 +236,8 @@ void JniCompilerTest::CompileAndRunStaticIntMethodThroughStubImpl() {
std::string reason;
ASSERT_TRUE(Runtime::Current()->GetJavaVM()->
- LoadNativeLibrary(env_, "", class_loader_, nullptr, nullptr, &reason))
+ LoadNativeLibrary(env_, "", class_loader_, /* is_shared_namespace */ false,
+ nullptr, nullptr, &reason))
<< reason;
jint result = env_->CallStaticIntMethod(jklass_, jmethod_, 42);
diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc
index 451aa682d6..7b7d46caa2 100644
--- a/compiler/oat_test.cc
+++ b/compiler/oat_test.cc
@@ -224,8 +224,9 @@ TEST_F(OatTest, WriteRead) {
}
const char* descriptor = dex_file.GetClassDescriptor(class_def);
- mirror::Class* klass = class_linker->FindClass(soa.Self(), descriptor,
- NullHandle<mirror::ClassLoader>());
+ mirror::Class* klass = class_linker->FindClass(soa.Self(),
+ descriptor,
+ ScopedNullHandle<mirror::ClassLoader>());
const OatFile::OatClass oat_class = oat_dex_file->GetOatClass(i);
CHECK_EQ(mirror::Class::Status::kStatusNotReady, oat_class.GetStatus()) << descriptor;
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index 2b2f0e8c26..53ac77b40f 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -737,7 +737,7 @@ class OatWriter::InitImageMethodVisitor : public OatDexMethodVisitor {
*dex_file_,
it.GetMemberIndex(),
dex_cache,
- NullHandle<mirror::ClassLoader>(),
+ ScopedNullHandle<mirror::ClassLoader>(),
nullptr,
invoke_type);
if (method == nullptr) {
diff --git a/compiler/optimizing/builder.h b/compiler/optimizing/builder.h
index ca71c32802..73e85bb5e3 100644
--- a/compiler/optimizing/builder.h
+++ b/compiler/optimizing/builder.h
@@ -80,7 +80,8 @@ class HGraphBuilder : public ValueObject {
can_use_baseline_for_string_init_(true),
compilation_stats_(nullptr),
interpreter_metadata_(nullptr),
- dex_cache_(NullHandle<mirror::DexCache>()) {}
+ null_dex_cache_(),
+ dex_cache_(null_dex_cache_) {}
bool BuildGraph(const DexFile::CodeItem& code);
@@ -371,6 +372,7 @@ class HGraphBuilder : public ValueObject {
const uint8_t* interpreter_metadata_;
// Dex cache for dex_file_.
+ ScopedNullHandle<mirror::DexCache> null_dex_cache_;
Handle<mirror::DexCache> dex_cache_;
DISALLOW_COPY_AND_ASSIGN(HGraphBuilder);
diff --git a/compiler/optimizing/gvn_test.cc b/compiler/optimizing/gvn_test.cc
index de60cf21aa..78cb7d410a 100644
--- a/compiler/optimizing/gvn_test.cc
+++ b/compiler/optimizing/gvn_test.cc
@@ -28,7 +28,7 @@ namespace art {
TEST(GVNTest, LocalFieldElimination) {
ArenaPool pool;
ArenaAllocator allocator(&pool);
- NullHandle<mirror::DexCache> dex_cache;
+ ScopedNullHandle<mirror::DexCache> dex_cache;
HGraph* graph = CreateGraph(&allocator);
HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
@@ -113,7 +113,7 @@ TEST(GVNTest, LocalFieldElimination) {
TEST(GVNTest, GlobalFieldElimination) {
ArenaPool pool;
ArenaAllocator allocator(&pool);
- NullHandle<mirror::DexCache> dex_cache;
+ ScopedNullHandle<mirror::DexCache> dex_cache;
HGraph* graph = CreateGraph(&allocator);
HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
@@ -196,7 +196,7 @@ TEST(GVNTest, GlobalFieldElimination) {
TEST(GVNTest, LoopFieldElimination) {
ArenaPool pool;
ArenaAllocator allocator(&pool);
- NullHandle<mirror::DexCache> dex_cache;
+ ScopedNullHandle<mirror::DexCache> dex_cache;
HGraph* graph = CreateGraph(&allocator);
HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
@@ -319,7 +319,7 @@ TEST(GVNTest, LoopFieldElimination) {
TEST(GVNTest, LoopSideEffects) {
ArenaPool pool;
ArenaAllocator allocator(&pool);
- NullHandle<mirror::DexCache> dex_cache;
+ ScopedNullHandle<mirror::DexCache> dex_cache;
static const SideEffects kCanTriggerGC = SideEffects::CanTriggerGC();
diff --git a/compiler/optimizing/licm_test.cc b/compiler/optimizing/licm_test.cc
index 2bb769a430..9ad003cc83 100644
--- a/compiler/optimizing/licm_test.cc
+++ b/compiler/optimizing/licm_test.cc
@@ -107,7 +107,7 @@ TEST_F(LICMTest, FieldHoisting) {
BuildLoop();
// Populate the loop with instructions: set/get field with different types.
- NullHandle<mirror::DexCache> dex_cache;
+ ScopedNullHandle<mirror::DexCache> dex_cache;
HInstruction* get_field = new (&allocator_) HInstanceFieldGet(parameter_,
Primitive::kPrimLong,
MemberOffset(10),
@@ -134,7 +134,7 @@ TEST_F(LICMTest, NoFieldHoisting) {
BuildLoop();
// Populate the loop with instructions: set/get field with same types.
- NullHandle<mirror::DexCache> dex_cache;
+ ScopedNullHandle<mirror::DexCache> dex_cache;
HInstruction* get_field = new (&allocator_) HInstanceFieldGet(parameter_,
Primitive::kPrimLong,
MemberOffset(10),
diff --git a/compiler/optimizing/load_store_elimination.cc b/compiler/optimizing/load_store_elimination.cc
index 2a2221a82c..727f2bb717 100644
--- a/compiler/optimizing/load_store_elimination.cc
+++ b/compiler/optimizing/load_store_elimination.cc
@@ -119,10 +119,16 @@ class HeapLocation : public ArenaObject<kArenaAllocMisc> {
: ref_info_(ref_info),
offset_(offset),
index_(index),
- declaring_class_def_index_(declaring_class_def_index) {
+ declaring_class_def_index_(declaring_class_def_index),
+ value_killed_by_loop_side_effects_(true) {
DCHECK(ref_info != nullptr);
DCHECK((offset == kInvalidFieldOffset && index != nullptr) ||
(offset != kInvalidFieldOffset && index == nullptr));
+ if (ref_info->IsSingleton() && !IsArrayElement()) {
+ // Assume this location's value cannot be killed by loop side effects
+ // until proven otherwise.
+ value_killed_by_loop_side_effects_ = false;
+ }
}
ReferenceInfo* GetReferenceInfo() const { return ref_info_; }
@@ -139,11 +145,22 @@ class HeapLocation : public ArenaObject<kArenaAllocMisc> {
return index_ != nullptr;
}
+ bool IsValueKilledByLoopSideEffects() const {
+ return value_killed_by_loop_side_effects_;
+ }
+
+ void SetValueKilledByLoopSideEffects(bool val) {
+ value_killed_by_loop_side_effects_ = val;
+ }
+
private:
ReferenceInfo* const ref_info_; // reference for instance/static field or array access.
const size_t offset_; // offset of static/instance field.
HInstruction* const index_; // index of an array element.
const int16_t declaring_class_def_index_; // declaring class's def's dex index.
+ bool value_killed_by_loop_side_effects_; // value of this location may be killed by loop
+ // side effects because this location is stored
+ // into inside a loop.
DISALLOW_COPY_AND_ASSIGN(HeapLocation);
};
@@ -370,13 +387,13 @@ class HeapLocationCollector : public HGraphVisitor {
return heap_locations_[heap_location_idx];
}
- void VisitFieldAccess(HInstruction* ref, const FieldInfo& field_info) {
+ HeapLocation* VisitFieldAccess(HInstruction* ref, const FieldInfo& field_info) {
if (field_info.IsVolatile()) {
has_volatile_ = true;
}
const uint16_t declaring_class_def_index = field_info.GetDeclaringClassDefIndex();
const size_t offset = field_info.GetFieldOffset().SizeValue();
- GetOrCreateHeapLocation(ref, offset, nullptr, declaring_class_def_index);
+ return GetOrCreateHeapLocation(ref, offset, nullptr, declaring_class_def_index);
}
void VisitArrayAccess(HInstruction* array, HInstruction* index) {
@@ -390,8 +407,11 @@ class HeapLocationCollector : public HGraphVisitor {
}
void VisitInstanceFieldSet(HInstanceFieldSet* instruction) OVERRIDE {
- VisitFieldAccess(instruction->InputAt(0), instruction->GetFieldInfo());
+ HeapLocation* location = VisitFieldAccess(instruction->InputAt(0), instruction->GetFieldInfo());
has_heap_stores_ = true;
+ if (instruction->GetBlock()->GetLoopInformation() != nullptr) {
+ location->SetValueKilledByLoopSideEffects(true);
+ }
}
void VisitStaticFieldGet(HStaticFieldGet* instruction) OVERRIDE {
@@ -565,23 +585,26 @@ class LSEVisitor : public HGraphVisitor {
HBasicBlock* pre_header = block->GetLoopInformation()->GetPreHeader();
ArenaVector<HInstruction*>& pre_header_heap_values =
heap_values_for_[pre_header->GetBlockId()];
+ // Inherit the values from pre-header.
+ for (size_t i = 0; i < heap_values.size(); i++) {
+ heap_values[i] = pre_header_heap_values[i];
+ }
+
// We do a single pass in reverse post order. For loops, use the side effects as a hint
// to see if the heap values should be killed.
if (side_effects_.GetLoopEffects(block).DoesAnyWrite()) {
- for (size_t i = 0; i < pre_header_heap_values.size(); i++) {
- // heap value is killed by loop side effects, need to keep the last store.
- KeepIfIsStore(pre_header_heap_values[i]);
- }
- if (kIsDebugBuild) {
- // heap_values should all be kUnknownHeapValue that it is inited with.
- for (size_t i = 0; i < heap_values.size(); i++) {
- DCHECK_EQ(heap_values[i], kUnknownHeapValue);
- }
- }
- } else {
- // Inherit the values from pre-header.
for (size_t i = 0; i < heap_values.size(); i++) {
- heap_values[i] = pre_header_heap_values[i];
+ HeapLocation* location = heap_location_collector_.GetHeapLocation(i);
+ ReferenceInfo* ref_info = location->GetReferenceInfo();
+ if (!ref_info->IsSingleton() || location->IsValueKilledByLoopSideEffects()) {
+ // heap value is killed by loop side effects (stored into directly, or due to
+ // aliasing).
+ KeepIfIsStore(pre_header_heap_values[i]);
+ heap_values[i] = kUnknownHeapValue;
+ } else {
+ // A singleton's field that's not stored into inside a loop is invariant throughout
+ // the loop.
+ }
}
}
}
@@ -762,6 +785,9 @@ class LSEVisitor : public HGraphVisitor {
if (loop_info != nullptr) {
// instruction is a store in the loop so the loop must does write.
DCHECK(side_effects_.GetLoopEffects(loop_info->GetHeader()).DoesAnyWrite());
+ // If it's a singleton, IsValueKilledByLoopSideEffects() must be true.
+ DCHECK(!ref_info->IsSingleton() ||
+ heap_location_collector_.GetHeapLocation(idx)->IsValueKilledByLoopSideEffects());
if (loop_info->IsDefinedOutOfTheLoop(original_ref)) {
DCHECK(original_ref->GetBlock()->Dominates(loop_info->GetPreHeader()));
diff --git a/compiler/optimizing/register_allocator_test.cc b/compiler/optimizing/register_allocator_test.cc
index 080f970756..8706854a6a 100644
--- a/compiler/optimizing/register_allocator_test.cc
+++ b/compiler/optimizing/register_allocator_test.cc
@@ -472,7 +472,7 @@ static HGraph* BuildIfElseWithPhi(ArenaAllocator* allocator,
HInstruction** input2) {
HGraph* graph = CreateGraph(allocator);
HBasicBlock* entry = new (allocator) HBasicBlock(graph);
- NullHandle<mirror::DexCache> dex_cache;
+ ScopedNullHandle<mirror::DexCache> dex_cache;
graph->AddBlock(entry);
graph->SetEntryBlock(entry);
HInstruction* parameter = new (allocator) HParameterValue(
@@ -624,7 +624,7 @@ static HGraph* BuildFieldReturn(ArenaAllocator* allocator,
HInstruction** field,
HInstruction** ret) {
HGraph* graph = CreateGraph(allocator);
- NullHandle<mirror::DexCache> dex_cache;
+ ScopedNullHandle<mirror::DexCache> dex_cache;
HBasicBlock* entry = new (allocator) HBasicBlock(graph);
graph->AddBlock(entry);
graph->SetEntryBlock(entry);
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index 58331296bf..bad928e9e8 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -2380,7 +2380,7 @@ class ImageDumper {
static int DumpImage(Runtime* runtime, const char* image_location, OatDumperOptions* options,
std::ostream* os) {
// Dumping the image, no explicit class loader.
- NullHandle<mirror::ClassLoader> null_class_loader;
+ ScopedNullHandle<mirror::ClassLoader> null_class_loader;
options->class_loader_ = &null_class_loader;
ScopedObjectAccess soa(Thread::Current());
@@ -2439,7 +2439,7 @@ static int DumpOatWithRuntime(Runtime* runtime, OatFile* oat_file, OatDumperOpti
static int DumpOatWithoutRuntime(OatFile* oat_file, OatDumperOptions* options, std::ostream* os) {
CHECK(oat_file != nullptr && options != nullptr);
// No image = no class loader.
- NullHandle<mirror::ClassLoader> null_class_loader;
+ ScopedNullHandle<mirror::ClassLoader> null_class_loader;
options->class_loader_ = &null_class_loader;
OatDumper oat_dumper(*oat_file, *options);
diff --git a/runtime/base/mutex.h b/runtime/base/mutex.h
index d4c9057ab3..263f50de51 100644
--- a/runtime/base/mutex.h
+++ b/runtime/base/mutex.h
@@ -63,6 +63,9 @@ enum LockLevel {
kLambdaTableLock,
kJdwpSocketLock,
kRegionSpaceRegionLock,
+ kRosAllocGlobalLock,
+ kRosAllocBracketLock,
+ kRosAllocBulkFreeLock,
kTransactionLogLock,
kMarkSweepMarkStackLock,
kJniWeakGlobalsLock,
@@ -73,9 +76,6 @@ enum LockLevel {
kReferenceQueueClearedReferencesLock,
kReferenceProcessorLock,
kJitCodeCacheLock,
- kRosAllocGlobalLock,
- kRosAllocBracketLock,
- kRosAllocBulkFreeLock,
kAllocSpaceLock,
kBumpPointerSpaceBlockLock,
kArenaPoolLock,
diff --git a/runtime/class_linker-inl.h b/runtime/class_linker-inl.h
index a5d10b265f..ea1afa8203 100644
--- a/runtime/class_linker-inl.h
+++ b/runtime/class_linker-inl.h
@@ -30,7 +30,7 @@
namespace art {
inline mirror::Class* ClassLinker::FindSystemClass(Thread* self, const char* descriptor) {
- return FindClass(self, descriptor, NullHandle<mirror::ClassLoader>());
+ return FindClass(self, descriptor, ScopedNullHandle<mirror::ClassLoader>());
}
inline mirror::Class* ClassLinker::FindArrayClass(Thread* self, mirror::Class** element_class) {
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index b9228f5945..d998d99539 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -1439,8 +1439,12 @@ bool ClassLinker::FindClassInPathClassLoader(ScopedObjectAccessAlreadyRunnable&
if (klass != nullptr) {
*result = EnsureResolved(self, descriptor, klass);
} else {
- *result = DefineClass(self, descriptor, hash, NullHandle<mirror::ClassLoader>(),
- *pair.first, *pair.second);
+ *result = DefineClass(self,
+ descriptor,
+ hash,
+ ScopedNullHandle<mirror::ClassLoader>(),
+ *pair.first,
+ *pair.second);
}
if (*result == nullptr) {
CHECK(self->IsExceptionPending()) << descriptor;
@@ -1565,7 +1569,11 @@ mirror::Class* ClassLinker::FindClass(Thread* self,
// The boot class loader, search the boot class path.
ClassPathEntry pair = FindInClassPath(descriptor, hash, boot_class_path_);
if (pair.second != nullptr) {
- return DefineClass(self, descriptor, hash, NullHandle<mirror::ClassLoader>(), *pair.first,
+ return DefineClass(self,
+ descriptor,
+ hash,
+ ScopedNullHandle<mirror::ClassLoader>(),
+ *pair.first,
*pair.second);
} else {
// The boot class loader is searched ahead of the application class loader, failures are
@@ -5459,7 +5467,8 @@ bool ClassLinker::LinkInterfaceMethods(
auto method_array(hs2.NewHandle(iftable->GetMethodArray(i)));
ArraySlice<ArtMethod> input_virtual_methods;
- Handle<mirror::PointerArray> input_vtable_array = NullHandle<mirror::PointerArray>();
+ ScopedNullHandle<mirror::PointerArray> null_handle;
+ Handle<mirror::PointerArray> input_vtable_array(null_handle);
int32_t input_array_length = 0;
// TODO Cleanup Needed: In the presence of default methods this optimization is rather dirty
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index 387ac0aee2..59a43ee206 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -855,7 +855,7 @@ TEST_F(ClassLinkerTest, ValidateBoxedTypes) {
// Validate that the "value" field is always the 0th field in each of java.lang's box classes.
// This lets UnboxPrimitive avoid searching for the field by name at runtime.
ScopedObjectAccess soa(Thread::Current());
- NullHandle<mirror::ClassLoader> class_loader;
+ ScopedNullHandle<mirror::ClassLoader> class_loader;
mirror::Class* c;
c = class_linker_->FindClass(soa.Self(), "Ljava/lang/Boolean;", class_loader);
EXPECT_STREQ("value", c->GetIFieldsPtr()->At(0).GetName());
@@ -1101,7 +1101,7 @@ TEST_F(ClassLinkerTest, ClassRootDescriptors) {
TEST_F(ClassLinkerTest, ValidatePredefinedClassSizes) {
ScopedObjectAccess soa(Thread::Current());
- NullHandle<mirror::ClassLoader> class_loader;
+ ScopedNullHandle<mirror::ClassLoader> class_loader;
mirror::Class* c;
c = class_linker_->FindClass(soa.Self(), "Ljava/lang/Class;", class_loader);
diff --git a/runtime/dex_file.cc b/runtime/dex_file.cc
index 880d3e0dea..bc8ba97a22 100644
--- a/runtime/dex_file.cc
+++ b/runtime/dex_file.cc
@@ -1383,8 +1383,11 @@ mirror::Class* DexFile::GetDeclaringClass(Handle<mirror::Class> klass) const {
if (annotation_item == nullptr) {
return nullptr;
}
- mirror::Object* obj = GetAnnotationValue(
- klass, annotation_item, "value", NullHandle<mirror::Class>(), kDexAnnotationType);
+ mirror::Object* obj = GetAnnotationValue(klass,
+ annotation_item,
+ "value",
+ ScopedNullHandle<mirror::Class>(),
+ kDexAnnotationType);
if (obj == nullptr) {
return nullptr;
}
@@ -1410,8 +1413,11 @@ mirror::Class* DexFile::GetEnclosingClass(Handle<mirror::Class> klass) const {
return nullptr;
}
AnnotationValue annotation_value;
- if (!ProcessAnnotationValue(
- klass, &annotation, &annotation_value, NullHandle<mirror::Class>(), kAllRaw)) {
+ if (!ProcessAnnotationValue(klass,
+ &annotation,
+ &annotation_value,
+ ScopedNullHandle<mirror::Class>(),
+ kAllRaw)) {
return nullptr;
}
if (annotation_value.type_ != kDexAnnotationMethod) {
@@ -1439,7 +1445,7 @@ mirror::Object* DexFile::GetEnclosingMethod(Handle<mirror::Class> klass) const {
return nullptr;
}
return GetAnnotationValue(
- klass, annotation_item, "value", NullHandle<mirror::Class>(), kDexAnnotationMethod);
+ klass, annotation_item, "value", ScopedNullHandle<mirror::Class>(), kDexAnnotationMethod);
}
bool DexFile::GetInnerClass(Handle<mirror::Class> klass, mirror::String** name) const {
@@ -1457,8 +1463,11 @@ bool DexFile::GetInnerClass(Handle<mirror::Class> klass, mirror::String** name)
return false;
}
AnnotationValue annotation_value;
- if (!ProcessAnnotationValue(
- klass, &annotation, &annotation_value, NullHandle<mirror::Class>(), kAllObjects)) {
+ if (!ProcessAnnotationValue(klass,
+ &annotation,
+ &annotation_value,
+ ScopedNullHandle<mirror::Class>(),
+ kAllObjects)) {
return false;
}
if (annotation_value.type_ != kDexAnnotationNull &&
@@ -1484,8 +1493,11 @@ bool DexFile::GetInnerClassFlags(Handle<mirror::Class> klass, uint32_t* flags) c
return false;
}
AnnotationValue annotation_value;
- if (!ProcessAnnotationValue(
- klass, &annotation, &annotation_value, NullHandle<mirror::Class>(), kAllRaw)) {
+ if (!ProcessAnnotationValue(klass,
+ &annotation,
+ &annotation_value,
+ ScopedNullHandle<mirror::Class>(),
+ kAllRaw)) {
return false;
}
if (annotation_value.type_ != kDexAnnotationInt) {
diff --git a/runtime/gc/collector/semi_space.cc b/runtime/gc/collector/semi_space.cc
index e9497a2223..99e98bb56a 100644
--- a/runtime/gc/collector/semi_space.cc
+++ b/runtime/gc/collector/semi_space.cc
@@ -367,37 +367,26 @@ void SemiSpace::MarkReachableObjects() {
GetTimings());
table->UpdateAndMarkReferences(this);
DCHECK(GetHeap()->FindRememberedSetFromSpace(space) == nullptr);
- } else if (collect_from_space_only_ && space->GetLiveBitmap() != nullptr) {
- // If the space has no mod union table (the non-moving space and main spaces when the bump
- // pointer space only collection is enabled,) then we need to scan its live bitmap or dirty
- // cards as roots (including the objects on the live stack which have just marked in the live
- // bitmap above in MarkAllocStackAsLive().)
- DCHECK(space == heap_->GetNonMovingSpace() || space == heap_->GetPrimaryFreeListSpace())
- << "Space " << space->GetName() << " "
- << "generational_=" << generational_ << " "
- << "collect_from_space_only_=" << collect_from_space_only_;
+ } else if ((space->IsImageSpace() || collect_from_space_only_) &&
+ space->GetLiveBitmap() != nullptr) {
+ // If the space has no mod union table (the non-moving space, app image spaces, main spaces
+ // when the bump pointer space only collection is enabled,) then we need to scan its live
+ // bitmap or dirty cards as roots (including the objects on the live stack which have just
+ // marked in the live bitmap above in MarkAllocStackAsLive().)
accounting::RememberedSet* rem_set = GetHeap()->FindRememberedSetFromSpace(space);
- if (kUseRememberedSet) {
+ if (!space->IsImageSpace()) {
+ DCHECK(space == heap_->GetNonMovingSpace() || space == heap_->GetPrimaryFreeListSpace())
+ << "Space " << space->GetName() << " "
+ << "generational_=" << generational_ << " "
+ << "collect_from_space_only_=" << collect_from_space_only_;
// App images currently do not have remembered sets.
- DCHECK((space->IsImageSpace() && space != heap_->GetBootImageSpace()) ||
- rem_set != nullptr);
+ DCHECK_EQ(kUseRememberedSet, rem_set != nullptr);
} else {
DCHECK(rem_set == nullptr);
}
if (rem_set != nullptr) {
TimingLogger::ScopedTiming t2("UpdateAndMarkRememberedSet", GetTimings());
rem_set->UpdateAndMarkReferences(from_space_, this);
- if (kIsDebugBuild) {
- // Verify that there are no from-space references that
- // remain in the space, that is, the remembered set (and the
- // card table) didn't miss any from-space references in the
- // space.
- accounting::ContinuousSpaceBitmap* live_bitmap = space->GetLiveBitmap();
- SemiSpaceVerifyNoFromSpaceReferencesObjectVisitor visitor(this);
- live_bitmap->VisitMarkedRange(reinterpret_cast<uintptr_t>(space->Begin()),
- reinterpret_cast<uintptr_t>(space->End()),
- visitor);
- }
} else {
TimingLogger::ScopedTiming t2("VisitLiveBits", GetTimings());
accounting::ContinuousSpaceBitmap* live_bitmap = space->GetLiveBitmap();
@@ -406,6 +395,17 @@ void SemiSpace::MarkReachableObjects() {
reinterpret_cast<uintptr_t>(space->End()),
visitor);
}
+ if (kIsDebugBuild) {
+ // Verify that there are no from-space references that
+ // remain in the space, that is, the remembered set (and the
+ // card table) didn't miss any from-space references in the
+ // space.
+ accounting::ContinuousSpaceBitmap* live_bitmap = space->GetLiveBitmap();
+ SemiSpaceVerifyNoFromSpaceReferencesObjectVisitor visitor(this);
+ live_bitmap->VisitMarkedRange(reinterpret_cast<uintptr_t>(space->Begin()),
+ reinterpret_cast<uintptr_t>(space->End()),
+ visitor);
+ }
}
}
diff --git a/runtime/gc/reference_queue_test.cc b/runtime/gc/reference_queue_test.cc
index ab921d95f1..dc23afed1d 100644
--- a/runtime/gc/reference_queue_test.cc
+++ b/runtime/gc/reference_queue_test.cc
@@ -35,7 +35,7 @@ TEST_F(ReferenceQueueTest, EnqueueDequeue) {
ASSERT_EQ(queue.GetLength(), 0U);
auto ref_class = hs.NewHandle(
Runtime::Current()->GetClassLinker()->FindClass(self, "Ljava/lang/ref/WeakReference;",
- NullHandle<mirror::ClassLoader>()));
+ ScopedNullHandle<mirror::ClassLoader>()));
ASSERT_TRUE(ref_class.Get() != nullptr);
auto ref1(hs.NewHandle(ref_class->AllocObject(self)->AsReference()));
ASSERT_TRUE(ref1.Get() != nullptr);
@@ -65,11 +65,11 @@ TEST_F(ReferenceQueueTest, Dump) {
queue.Dump(LOG(INFO));
auto weak_ref_class = hs.NewHandle(
Runtime::Current()->GetClassLinker()->FindClass(self, "Ljava/lang/ref/WeakReference;",
- NullHandle<mirror::ClassLoader>()));
+ ScopedNullHandle<mirror::ClassLoader>()));
ASSERT_TRUE(weak_ref_class.Get() != nullptr);
auto finalizer_ref_class = hs.NewHandle(
Runtime::Current()->GetClassLinker()->FindClass(self, "Ljava/lang/ref/FinalizerReference;",
- NullHandle<mirror::ClassLoader>()));
+ ScopedNullHandle<mirror::ClassLoader>()));
ASSERT_TRUE(finalizer_ref_class.Get() != nullptr);
auto ref1(hs.NewHandle(weak_ref_class->AllocObject(self)->AsReference()));
ASSERT_TRUE(ref1.Get() != nullptr);
diff --git a/runtime/handle.h b/runtime/handle.h
index f939ec5018..5b3bb60dfa 100644
--- a/runtime/handle.h
+++ b/runtime/handle.h
@@ -64,7 +64,7 @@ class Handle : public ValueObject {
ALWAYS_INLINE jobject ToJObject() const SHARED_REQUIRES(Locks::mutator_lock_) {
if (UNLIKELY(reference_->AsMirrorPtr() == nullptr)) {
- // Special case so that we work with NullHandles.
+ // Special case so that we work with null handles.
return nullptr;
}
return reinterpret_cast<jobject>(reference_);
@@ -147,12 +147,12 @@ class MutableHandle : public Handle<T> {
template<size_t kNumReferences> friend class StackHandleScope;
};
-// A special case of Handle that only holds references to null.
+// A special case of Handle that only holds references to null. Invalid when if it goes out of
+// scope. Example: Handle<T> h = ScopedNullHandle<T> will leave h being undefined.
template<class T>
-class NullHandle : public Handle<T> {
+class ScopedNullHandle : public Handle<T> {
public:
- NullHandle() : Handle<T>(&null_ref_) {
- }
+ ScopedNullHandle() : Handle<T>(&null_ref_) {}
private:
StackReference<mirror::Object> null_ref_;
diff --git a/runtime/interpreter/unstarted_runtime.cc b/runtime/interpreter/unstarted_runtime.cc
index 92b6e4fe0d..60ad0cbb10 100644
--- a/runtime/interpreter/unstarted_runtime.cc
+++ b/runtime/interpreter/unstarted_runtime.cc
@@ -128,8 +128,13 @@ void UnstartedRuntime::UnstartedClassForName(
}
StackHandleScope<1> hs(self);
Handle<mirror::String> h_class_name(hs.NewHandle(class_name));
- UnstartedRuntimeFindClass(self, h_class_name, NullHandle<mirror::ClassLoader>(), result,
- "Class.forName", true, false);
+ UnstartedRuntimeFindClass(self,
+ h_class_name,
+ ScopedNullHandle<mirror::ClassLoader>(),
+ result,
+ "Class.forName",
+ true,
+ false);
CheckExceptionGenerateClassNotFound(self);
}
@@ -704,7 +709,7 @@ void UnstartedRuntime::UnstartedSecurityGetSecurityPropertiesReader(
Handle<mirror::Class> h_class(hs.NewHandle(
runtime->GetClassLinker()->FindClass(self,
"Ljava/io/StringReader;",
- NullHandle<mirror::ClassLoader>())));
+ ScopedNullHandle<mirror::ClassLoader>())));
if (h_class.Get() == nullptr) {
AbortTransactionOrFail(self, "Could not find StringReader class");
return;
diff --git a/runtime/java_vm_ext.cc b/runtime/java_vm_ext.cc
index 15f51220e4..5c4419333b 100644
--- a/runtime/java_vm_ext.cc
+++ b/runtime/java_vm_ext.cc
@@ -717,8 +717,8 @@ void JavaVMExt::UnloadNativeLibraries() {
}
bool JavaVMExt::LoadNativeLibrary(JNIEnv* env, const std::string& path, jobject class_loader,
- jstring library_path, jstring permitted_path,
- std::string* error_msg) {
+ bool is_shared_namespace, jstring library_path,
+ jstring permitted_path, std::string* error_msg) {
error_msg->clear();
// See if we've already loaded this library. If we have, and the class loader
@@ -777,8 +777,9 @@ bool JavaVMExt::LoadNativeLibrary(JNIEnv* env, const std::string& path, jobject
Locks::mutator_lock_->AssertNotHeld(self);
const char* path_str = path.empty() ? nullptr : path.c_str();
- void* handle = android::OpenNativeLibrary(env, runtime_->GetTargetSdkVersion(),
- path_str, class_loader, library_path, permitted_path);
+ void* handle = android::OpenNativeLibrary(env, runtime_->GetTargetSdkVersion(), path_str,
+ class_loader, is_shared_namespace, library_path,
+ permitted_path);
bool needs_native_bridge = false;
if (handle == nullptr) {
if (android::NativeBridgeIsSupported(path_str)) {
diff --git a/runtime/java_vm_ext.h b/runtime/java_vm_ext.h
index 85597695af..8cae1e52d2 100644
--- a/runtime/java_vm_ext.h
+++ b/runtime/java_vm_ext.h
@@ -85,8 +85,9 @@ class JavaVMExt : public JavaVM {
* Returns 'true' on success. On failure, sets 'error_msg' to a
* human-readable description of the error.
*/
- bool LoadNativeLibrary(JNIEnv* env, const std::string& path, jobject javaLoader,
- jstring library_path, jstring permitted_path, std::string* error_msg);
+ bool LoadNativeLibrary(JNIEnv* env, const std::string& path, jobject class_loader,
+ bool is_shared_namespace, jstring library_path, jstring permitted_path,
+ std::string* error_msg);
// Unload native libraries with cleared class loaders.
void UnloadNativeLibraries()
diff --git a/runtime/jit/jit.cc b/runtime/jit/jit.cc
index 4b39c03e0c..b2fc74d4f4 100644
--- a/runtime/jit/jit.cc
+++ b/runtime/jit/jit.cc
@@ -177,22 +177,13 @@ void Jit::SaveProfilingInfo(const std::string& filename) {
if (offline_profile_info_ == nullptr) {
return;
}
- // Note that we can't check the PrimaryOatFile when constructing the offline_profilie_info_
- // because it becomes known to the Runtime after we create and initialize the JIT.
- const OatFile* primary_oat_file = Runtime::Current()->GetOatFileManager().GetPrimaryOatFile();
- if (primary_oat_file == nullptr) {
- LOG(WARNING) << "Couldn't find a primary oat file when trying to save profile info to "
- << filename;
- return;
- }
-
uint64_t last_update_ns = code_cache_->GetLastUpdateTimeNs();
if (offline_profile_info_->NeedsSaving(last_update_ns)) {
VLOG(profiler) << "Initiate save profiling information to: " << filename;
std::set<ArtMethod*> methods;
{
ScopedObjectAccess soa(Thread::Current());
- code_cache_->GetCompiledArtMethods(primary_oat_file, methods);
+ code_cache_->GetCompiledArtMethods(offline_profile_info_->GetTrackedDexLocations(), methods);
}
offline_profile_info_->SaveProfilingInfo(filename, last_update_ns, methods);
} else {
@@ -219,5 +210,12 @@ void Jit::CreateInstrumentationCache(size_t compile_threshold, size_t warmup_thr
new jit::JitInstrumentationCache(compile_threshold, warmup_threshold));
}
+void Jit::SetDexLocationsForProfiling(const std::vector<std::string>& dex_base_locations) {
+ if (offline_profile_info_ == nullptr) {
+ return;
+ }
+ offline_profile_info_->SetTrackedDexLocations(dex_base_locations);
+}
+
} // namespace jit
} // namespace art
diff --git a/runtime/jit/jit.h b/runtime/jit/jit.h
index e80a376349..7a2db31fc0 100644
--- a/runtime/jit/jit.h
+++ b/runtime/jit/jit.h
@@ -72,6 +72,7 @@ class Jit {
return instrumentation_cache_.get();
}
+ void SetDexLocationsForProfiling(const std::vector<std::string>& dex_locations);
void SaveProfilingInfo(const std::string& filename);
void DumpForSigQuit(std::ostream& os) {
diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc
index 3342e92a79..033a8f05d8 100644
--- a/runtime/jit/jit_code_cache.cc
+++ b/runtime/jit/jit_code_cache.cc
@@ -19,6 +19,7 @@
#include <sstream>
#include "art_method-inl.h"
+#include "base/stl_util.h"
#include "base/time_utils.h"
#include "entrypoints/runtime_asm_entrypoints.h"
#include "gc/accounting/bitmap-inl.h"
@@ -687,11 +688,11 @@ void* JitCodeCache::MoreCore(const void* mspace, intptr_t increment) NO_THREAD_S
}
}
-void JitCodeCache::GetCompiledArtMethods(const OatFile* oat_file,
+void JitCodeCache::GetCompiledArtMethods(const std::set<const std::string>& dex_base_locations,
std::set<ArtMethod*>& methods) {
MutexLock mu(Thread::Current(), lock_);
for (auto it : method_code_map_) {
- if (it.second->GetDexFile()->GetOatDexFile()->GetOatFile() == oat_file) {
+ if (ContainsElement(dex_base_locations, it.second->GetDexFile()->GetBaseLocation())) {
methods.insert(it.second);
}
}
diff --git a/runtime/jit/jit_code_cache.h b/runtime/jit/jit_code_cache.h
index 93ccb7401d..0ceb17ae74 100644
--- a/runtime/jit/jit_code_cache.h
+++ b/runtime/jit/jit_code_cache.h
@@ -146,8 +146,9 @@ class JitCodeCache {
void* MoreCore(const void* mspace, intptr_t increment);
- // Adds to `methods` all the compiled ArtMethods which are part of the given `oat_file`.
- void GetCompiledArtMethods(const OatFile* oat_file, std::set<ArtMethod*>& methods)
+ // Adds to `methods` all the compiled ArtMethods which are part of any of the given dex locations.
+ void GetCompiledArtMethods(const std::set<const std::string>& dex_base_locations,
+ std::set<ArtMethod*>& methods)
REQUIRES(!lock_)
SHARED_REQUIRES(Locks::mutator_lock_);
diff --git a/runtime/jit/offline_profiling_info.cc b/runtime/jit/offline_profiling_info.cc
index 761587024c..511b53d5db 100644
--- a/runtime/jit/offline_profiling_info.cc
+++ b/runtime/jit/offline_profiling_info.cc
@@ -24,9 +24,9 @@
#include "art_method-inl.h"
#include "base/mutex.h"
+#include "base/stl_util.h"
#include "jit/profiling_info.h"
#include "safe_map.h"
-#include "utils.h"
namespace art {
@@ -34,8 +34,20 @@ namespace art {
static constexpr const uint64_t kMilisecondsToNano = 1000000;
static constexpr const uint64_t kMinimumTimeBetweenSavesNs = 500 * kMilisecondsToNano;
+void OfflineProfilingInfo::SetTrackedDexLocations(
+ const std::vector<std::string>& dex_base_locations) {
+ tracked_dex_base_locations_.clear();
+ tracked_dex_base_locations_.insert(dex_base_locations.begin(), dex_base_locations.end());
+ VLOG(profiler) << "Tracking dex locations: " << Join(dex_base_locations, ':');
+}
+
+const std::set<const std::string>& OfflineProfilingInfo::GetTrackedDexLocations() const {
+ return tracked_dex_base_locations_;
+}
+
bool OfflineProfilingInfo::NeedsSaving(uint64_t last_update_time_ns) const {
- return last_update_time_ns - last_update_time_ns_.LoadRelaxed() > kMinimumTimeBetweenSavesNs;
+ return !tracked_dex_base_locations_.empty() &&
+ (last_update_time_ns - last_update_time_ns_.LoadRelaxed() > kMinimumTimeBetweenSavesNs);
}
void OfflineProfilingInfo::SaveProfilingInfo(const std::string& filename,
@@ -55,6 +67,7 @@ void OfflineProfilingInfo::SaveProfilingInfo(const std::string& filename,
{
ScopedObjectAccess soa(Thread::Current());
for (auto it = methods.begin(); it != methods.end(); it++) {
+ DCHECK(ContainsElement(tracked_dex_base_locations_, (*it)->GetDexFile()->GetBaseLocation()));
AddMethodInfo(*it, &info);
}
}
@@ -146,11 +159,11 @@ static constexpr const char kLineSeparator = '\n';
/**
* Serialization format:
- * multidex_suffix1,dex_location_checksum1,method_id11,method_id12...
- * multidex_suffix2,dex_location_checksum2,method_id21,method_id22...
+ * dex_location1,dex_location_checksum1,method_id11,method_id12...
+ * dex_location2,dex_location_checksum2,method_id21,method_id22...
* e.g.
- * ,131232145,11,23,454,54 -> this is the first dex file, it has no multidex suffix
- * :classes5.dex,218490184,39,13,49,1 -> this is the fifth dex file.
+ * /system/priv-app/app/app.apk,131232145,11,23,454,54
+ * /system/priv-app/app/app.apk:classes5.dex,218490184,39,13,49,1
**/
bool OfflineProfilingInfo::Serialize(const std::string& filename,
const DexFileToMethodsMap& info) const {
@@ -167,7 +180,7 @@ bool OfflineProfilingInfo::Serialize(const std::string& filename,
const DexFile* dex_file = it.first;
const std::set<uint32_t>& method_dex_ids = it.second;
- os << DexFile::GetMultiDexSuffix(dex_file->GetLocation())
+ os << dex_file->GetLocation()
<< kFieldSeparator
<< dex_file->GetLocationChecksum();
for (auto method_it : method_dex_ids) {
@@ -214,7 +227,7 @@ bool ProfileCompilationInfo::ProcessLine(const std::string& line,
return false;
}
- const std::string& multidex_suffix = parts[0];
+ const std::string& dex_location = parts[0];
uint32_t checksum;
if (!ParseInt(parts[1].c_str(), &checksum)) {
return false;
@@ -222,7 +235,7 @@ bool ProfileCompilationInfo::ProcessLine(const std::string& line,
const DexFile* current_dex_file = nullptr;
for (auto dex_file : dex_files) {
- if (DexFile::GetMultiDexSuffix(dex_file->GetLocation()) == multidex_suffix) {
+ if (dex_file->GetLocation() == dex_location) {
if (checksum != dex_file->GetLocationChecksum()) {
LOG(WARNING) << "Checksum mismatch for "
<< dex_file->GetLocation() << " when parsing " << filename_;
@@ -284,15 +297,15 @@ bool ProfileCompilationInfo::Load(const std::vector<const DexFile*>& dex_files)
return true;
}
if (kIsDebugBuild) {
- // In debug builds verify that the multidex suffixes are unique.
- std::set<std::string> suffixes;
+ // In debug builds verify that the locations are unique.
+ std::set<std::string> locations;
for (auto dex_file : dex_files) {
- std::string multidex_suffix = DexFile::GetMultiDexSuffix(dex_file->GetLocation());
- DCHECK(suffixes.find(multidex_suffix) == suffixes.end())
+ const std::string& location = dex_file->GetLocation();
+ DCHECK(locations.find(location) == locations.end())
<< "DexFiles appear to belong to different apks."
- << " There are multiple dex files with the same multidex suffix: "
- << multidex_suffix;
- suffixes.insert(multidex_suffix);
+ << " There are multiple dex files with the same location: "
+ << location;
+ locations.insert(location);
}
}
info_.clear();
diff --git a/runtime/jit/offline_profiling_info.h b/runtime/jit/offline_profiling_info.h
index 90bda60ac7..8c5ffbe635 100644
--- a/runtime/jit/offline_profiling_info.h
+++ b/runtime/jit/offline_profiling_info.h
@@ -40,6 +40,8 @@ class OfflineProfilingInfo {
void SaveProfilingInfo(const std::string& filename,
uint64_t last_update_time_ns,
const std::set<ArtMethod*>& methods);
+ void SetTrackedDexLocations(const std::vector<std::string>& dex_locations);
+ const std::set<const std::string>& GetTrackedDexLocations() const;
private:
// Map identifying the location of the profiled methods.
@@ -53,6 +55,8 @@ class OfflineProfilingInfo {
// TODO(calin): Verify if Atomic is really needed (are we sure to be called from a
// single thread?)
Atomic<uint64_t> last_update_time_ns_;
+
+ std::set<const std::string> tracked_dex_base_locations_;
};
/**
diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc
index b49d68f6ce..424cc11da9 100644
--- a/runtime/native/dalvik_system_VMRuntime.cc
+++ b/runtime/native/dalvik_system_VMRuntime.cc
@@ -566,17 +566,25 @@ static void VMRuntime_preloadDexCaches(JNIEnv* env, jobject) {
*/
static void VMRuntime_registerAppInfo(JNIEnv* env,
jclass clazz ATTRIBUTE_UNUSED,
- jstring pkgName,
- jstring appDir,
- jstring procName ATTRIBUTE_UNUSED) {
- const char* appDirChars = env->GetStringUTFChars(appDir, nullptr);
- const char* pkgNameChars = env->GetStringUTFChars(pkgName, nullptr);
- std::string profileFile = StringPrintf("%s/code_cache/%s.prof", appDirChars, pkgNameChars);
+ jstring pkg_name,
+ jstring app_dir,
+ jobjectArray code_paths) {
+ std::vector<std::string> code_paths_vec;
+ int code_paths_length = env->GetArrayLength(code_paths);
+ for (int i = 0; i < code_paths_length; i++) {
+ jstring code_path = reinterpret_cast<jstring>(env->GetObjectArrayElement(code_paths, i));
+ const char* raw_code_path = env->GetStringUTFChars(code_path, nullptr);
+ code_paths_vec.push_back(raw_code_path);
+ env->ReleaseStringUTFChars(code_path, raw_code_path);
+ }
- Runtime::Current()->SetJitProfilingFilename(profileFile.c_str());
+ const char* raw_app_dir = env->GetStringUTFChars(app_dir, nullptr);
+ const char* raw_pkg_name = env->GetStringUTFChars(pkg_name, nullptr);
+ std::string profile_file = StringPrintf("%s/code_cache/%s.prof", raw_app_dir, raw_pkg_name);
+ env->ReleaseStringUTFChars(pkg_name, raw_pkg_name);
+ env->ReleaseStringUTFChars(app_dir, raw_app_dir);
- env->ReleaseStringUTFChars(appDir, appDirChars);
- env->ReleaseStringUTFChars(pkgName, pkgNameChars);
+ Runtime::Current()->RegisterAppInfo(code_paths_vec, profile_file);
}
static jboolean VMRuntime_isBootClassPathOnDisk(JNIEnv* env, jclass, jstring java_instruction_set) {
@@ -633,7 +641,7 @@ static JNINativeMethod gMethods[] = {
NATIVE_METHOD(VMRuntime, isCheckJniEnabled, "!()Z"),
NATIVE_METHOD(VMRuntime, preloadDexCaches, "()V"),
NATIVE_METHOD(VMRuntime, registerAppInfo,
- "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"),
+ "(Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;)V"),
NATIVE_METHOD(VMRuntime, isBootClassPathOnDisk, "(Ljava/lang/String;)Z"),
NATIVE_METHOD(VMRuntime, getCurrentInstructionSet, "()Ljava/lang/String;"),
};
diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc
index 14d284e003..19774811bc 100644
--- a/runtime/native/java_lang_Class.cc
+++ b/runtime/native/java_lang_Class.cc
@@ -653,7 +653,8 @@ static jobject Class_newInstance(JNIEnv* env, jobject javaThis) {
}
}
auto* constructor = klass->GetDeclaredConstructor(
- soa.Self(), NullHandle<mirror::ObjectArray<mirror::Class>>());
+ soa.Self(),
+ ScopedNullHandle<mirror::ObjectArray<mirror::Class>>());
if (UNLIKELY(constructor == nullptr)) {
soa.Self()->ThrowNewExceptionF("Ljava/lang/InstantiationException;",
"%s has no zero argument constructor",
diff --git a/runtime/native/java_lang_Runtime.cc b/runtime/native/java_lang_Runtime.cc
index 4a1e6c21c1..f42a17d538 100644
--- a/runtime/native/java_lang_Runtime.cc
+++ b/runtime/native/java_lang_Runtime.cc
@@ -68,7 +68,8 @@ static void SetLdLibraryPath(JNIEnv* env, jstring javaLdLibraryPath) {
}
static jstring Runtime_nativeLoad(JNIEnv* env, jclass, jstring javaFilename, jobject javaLoader,
- jstring javaLdLibraryPath, jstring javaIsolationPath) {
+ jboolean isSharedNamespace, jstring javaLibrarySearchPath,
+ jstring javaLibraryPermittedPath) {
ScopedUtfChars filename(env, javaFilename);
if (filename.c_str() == nullptr) {
return nullptr;
@@ -80,14 +81,19 @@ static jstring Runtime_nativeLoad(JNIEnv* env, jclass, jstring javaFilename, job
// linker namespace instead of global LD_LIBRARY_PATH
// (23 is Marshmallow)
if (target_sdk_version <= INT_MAX) {
- SetLdLibraryPath(env, javaLdLibraryPath);
+ SetLdLibraryPath(env, javaLibrarySearchPath);
}
std::string error_msg;
{
JavaVMExt* vm = Runtime::Current()->GetJavaVM();
- bool success = vm->LoadNativeLibrary(env, filename.c_str(), javaLoader,
- javaLdLibraryPath, javaIsolationPath, &error_msg);
+ bool success = vm->LoadNativeLibrary(env,
+ filename.c_str(),
+ javaLoader,
+ isSharedNamespace == JNI_TRUE,
+ javaLibrarySearchPath,
+ javaLibraryPermittedPath,
+ &error_msg);
if (success) {
return nullptr;
}
@@ -115,7 +121,7 @@ static JNINativeMethod gMethods[] = {
NATIVE_METHOD(Runtime, gc, "()V"),
NATIVE_METHOD(Runtime, maxMemory, "!()J"),
NATIVE_METHOD(Runtime, nativeExit, "(I)V"),
- NATIVE_METHOD(Runtime, nativeLoad, "(Ljava/lang/String;Ljava/lang/ClassLoader;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"),
+ NATIVE_METHOD(Runtime, nativeLoad, "(Ljava/lang/String;Ljava/lang/ClassLoader;ZLjava/lang/String;Ljava/lang/String;)Ljava/lang/String;"),
NATIVE_METHOD(Runtime, totalMemory, "!()J"),
};
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 02747d0d4d..f3197c7cc4 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -1219,7 +1219,9 @@ void Runtime::InitNativeMethods() {
// the library that implements System.loadLibrary!
{
std::string error_msg;
- if (!java_vm_->LoadNativeLibrary(env, "libjavacore.so", nullptr, nullptr, nullptr, &error_msg)) {
+ if (!java_vm_->LoadNativeLibrary(env, "libjavacore.so", nullptr,
+ /* is_shared_namespace */ false,
+ nullptr, nullptr, &error_msg)) {
LOG(FATAL) << "LoadNativeLibrary failed for \"libjavacore.so\": " << error_msg;
}
}
@@ -1638,7 +1640,12 @@ void Runtime::SetCalleeSaveMethod(ArtMethod* method, CalleeSaveType type) {
callee_save_methods_[type] = reinterpret_cast<uintptr_t>(method);
}
-void Runtime::SetJitProfilingFilename(const char* profile_output_filename) {
+void Runtime::RegisterAppInfo(const std::vector<std::string>& code_paths,
+ const std::string& profile_output_filename) {
+ DCHECK(!profile_output_filename.empty());
+ if (jit_.get() != nullptr) {
+ jit_->SetDexLocationsForProfiling(code_paths);
+ }
profile_output_filename_ = profile_output_filename;
}
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 93d8fcfa46..b45408eab7 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -467,7 +467,8 @@ class Runtime {
return &instrumentation_;
}
- void SetJitProfilingFilename(const char* profile_output_filename);
+ void RegisterAppInfo(const std::vector<std::string>& code_paths,
+ const std::string& profile_output_filename);
void UpdateProfilerState(int state);
// Transaction support.
diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc
index 2b778d9b22..a47a08e9ed 100644
--- a/runtime/well_known_classes.cc
+++ b/runtime/well_known_classes.cc
@@ -381,7 +381,7 @@ void WellKnownClasses::LateInit(JNIEnv* env) {
ScopedLocalRef<jclass> java_lang_Runtime(env, env->FindClass("java/lang/Runtime"));
java_lang_Runtime_nativeLoad =
CacheMethod(env, java_lang_Runtime.get(), true, "nativeLoad",
- "(Ljava/lang/String;Ljava/lang/ClassLoader;Ljava/lang/String;Ljava/lang/String;)"
+ "(Ljava/lang/String;Ljava/lang/ClassLoader;ZLjava/lang/String;Ljava/lang/String;)"
"Ljava/lang/String;");
}
diff --git a/test/530-checker-lse/src/Main.java b/test/530-checker-lse/src/Main.java
index 7d89372a96..cadf706c16 100644
--- a/test/530-checker-lse/src/Main.java
+++ b/test/530-checker-lse/src/Main.java
@@ -489,27 +489,32 @@ public class Main {
return obj;
}
- /// CHECK-START: void Main.test21() load_store_elimination (before)
+ /// CHECK-START: void Main.test21(TestClass) load_store_elimination (before)
/// CHECK: NewInstance
/// CHECK: InstanceFieldSet
- /// CHECK: StaticFieldSet
- /// CHECK: StaticFieldGet
+ /// CHECK: InstanceFieldSet
+ /// CHECK: InstanceFieldSet
+ /// CHECK: InstanceFieldGet
+ /// CHECK: InstanceFieldGet
- /// CHECK-START: void Main.test21() load_store_elimination (after)
+ /// CHECK-START: void Main.test21(TestClass) load_store_elimination (after)
/// CHECK: NewInstance
/// CHECK: InstanceFieldSet
- /// CHECK: StaticFieldSet
+ /// CHECK: InstanceFieldSet
+ /// CHECK: InstanceFieldSet
+ /// CHECK: InstanceFieldGet
/// CHECK: InstanceFieldGet
// Loop side effects can kill heap values, stores need to be kept in that case.
- static void test21() {
+ static void test21(TestClass obj0) {
TestClass obj = new TestClass();
+ obj0.str = "abc";
obj.str = "abc";
for (int i = 0; i < 2; i++) {
- // Generate some loop side effect that does write.
- obj.si = 1;
+ // Generate some loop side effect that writes into obj.
+ obj.str = "def";
}
- System.out.print(obj.str.substring(0, 0));
+ System.out.print(obj0.str.substring(0, 0) + obj.str.substring(0, 0));
}
/// CHECK-START: int Main.test22() load_store_elimination (before)
@@ -525,27 +530,29 @@ public class Main {
/// CHECK-START: int Main.test22() load_store_elimination (after)
/// CHECK: NewInstance
- /// CHECK: InstanceFieldSet
+ /// CHECK-NOT: InstanceFieldSet
/// CHECK: NewInstance
/// CHECK-NOT: InstanceFieldSet
/// CHECK-NOT: InstanceFieldGet
/// CHECK: NewInstance
/// CHECK-NOT: InstanceFieldSet
- /// CHECK: InstanceFieldGet
+ /// CHECK-NOT: InstanceFieldGet
/// CHECK-NOT: InstanceFieldGet
- // Loop side effects only affects stores into singletons that dominiates the loop header.
+ // For a singleton, loop side effects can kill its field values only if:
+ // (1) it dominiates the loop header, and
+ // (2) its fields are stored into inside a loop.
static int test22() {
int sum = 0;
TestClass obj1 = new TestClass();
- obj1.i = 2; // This store can't be eliminated since it can be killed by loop side effects.
+ obj1.i = 2; // This store can be eliminated since obj1 is never stored into inside a loop.
for (int i = 0; i < 2; i++) {
TestClass obj2 = new TestClass();
- obj2.i = 3; // This store can be eliminated since the singleton is inside the loop.
+ obj2.i = 3; // This store can be eliminated since the singleton is inside the loop.
sum += obj2.i;
}
TestClass obj3 = new TestClass();
- obj3.i = 5; // This store can be eliminated since the singleton is created after the loop.
+ obj3.i = 5; // This store can be eliminated since the singleton is created after the loop.
sum += obj1.i + obj3.i;
return sum;
}
@@ -715,7 +722,7 @@ public class Main {
float[] fa2 = { 1.8f };
assertFloatEquals(test19(fa1, fa2), 1.8f);
assertFloatEquals(test20().i, 0);
- test21();
+ test21(new TestClass());
assertIntEquals(test22(), 13);
assertIntEquals(test23(true), 4);
assertIntEquals(test23(false), 5);