diff options
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); |