diff options
author | 2022-11-29 10:30:42 +0000 | |
---|---|---|
committer | 2022-11-30 15:38:00 +0000 | |
commit | 97de32773e20297125d4e35e5d7dcb3b6732e063 (patch) | |
tree | 0d1f79ef1a8b7f82f0b3d70311d0b2ed85707244 | |
parent | 0110e952e488bc41429f6f33f36e8884f41a26d8 (diff) |
Change well known method `String.charAt()` to `ArtMethod*`.
Test: m test-art-host-gtest
Test: testrunner.py --host --optimizing
Change-Id: Idb34c5de408b98db746d385ae6e012a8997fcc96
-rw-r--r-- | compiler/optimizing/prepare_for_register_allocation.cc | 2 | ||||
-rw-r--r-- | libartbase/base/stl_util.h | 9 | ||||
-rw-r--r-- | libartbase/base/transform_iterator.h | 2 | ||||
-rw-r--r-- | runtime/entrypoints/entrypoint_utils-inl.h | 3 | ||||
-rw-r--r-- | runtime/entrypoints/quick/quick_trampoline_entrypoints.cc | 4 | ||||
-rw-r--r-- | runtime/native/dalvik_system_BaseDexClassLoader.cc | 40 | ||||
-rw-r--r-- | runtime/native/dalvik_system_DexFile.cc | 77 | ||||
-rw-r--r-- | runtime/native/dalvik_system_VMDebug.cc | 98 | ||||
-rw-r--r-- | runtime/native/dalvik_system_VMRuntime.cc | 24 | ||||
-rw-r--r-- | runtime/native/java_lang_VMClassLoader.cc | 59 | ||||
-rw-r--r-- | runtime/native/java_lang_reflect_Constructor.cc | 1 | ||||
-rw-r--r-- | runtime/native/java_lang_reflect_Method.cc | 1 | ||||
-rw-r--r-- | runtime/native/string_array_utils.h | 81 | ||||
-rw-r--r-- | runtime/reference_table_test.cc | 18 | ||||
-rw-r--r-- | runtime/well_known_classes.cc | 26 | ||||
-rw-r--r-- | runtime/well_known_classes.h | 4 |
16 files changed, 237 insertions, 212 deletions
diff --git a/compiler/optimizing/prepare_for_register_allocation.cc b/compiler/optimizing/prepare_for_register_allocation.cc index 91c1beac8e..5ce63284ae 100644 --- a/compiler/optimizing/prepare_for_register_allocation.cc +++ b/compiler/optimizing/prepare_for_register_allocation.cc @@ -83,7 +83,7 @@ void PrepareForRegisterAllocation::VisitBoundsCheck(HBoundsCheck* check) { if (check->IsStringCharAt()) { // Add a fake environment for String.charAt() inline info as we want the exception // to appear as being thrown from there. Skip if we're compiling String.charAt() itself. - ArtMethod* char_at_method = jni::DecodeArtMethod(WellKnownClasses::java_lang_String_charAt); + ArtMethod* char_at_method = WellKnownClasses::java_lang_String_charAt; if (GetGraph()->GetArtMethod() != char_at_method) { ArenaAllocator* allocator = GetGraph()->GetAllocator(); HEnvironment* environment = new (allocator) HEnvironment(allocator, diff --git a/libartbase/base/stl_util.h b/libartbase/base/stl_util.h index 0ae4fd26aa..2c9547f020 100644 --- a/libartbase/base/stl_util.h +++ b/libartbase/base/stl_util.h @@ -278,11 +278,10 @@ struct FilterIterator std::optional<RealIter> end_; }; -template <typename Iter, typename Filter> -static inline IterationRange<FilterIterator<Iter, Filter>> Filter( - IterationRange<Iter> it, Filter cond) { - auto end = it.end(); - auto start = std::find_if(it.begin(), end, cond); +template <typename BaseRange, typename Filter> +static inline auto Filter(BaseRange&& range, Filter cond) { + auto end = range.end(); + auto start = std::find_if(range.begin(), end, cond); return MakeIterationRange(FilterIterator(start, cond, std::make_optional(end)), FilterIterator(end, cond, std::make_optional(end))); } diff --git a/libartbase/base/transform_iterator.h b/libartbase/base/transform_iterator.h index 062c88b629..552f31fa3b 100644 --- a/libartbase/base/transform_iterator.h +++ b/libartbase/base/transform_iterator.h @@ -160,7 +160,7 @@ TransformIterator<BaseIterator, Function> MakeTransformIterator(BaseIterator bas } template <typename BaseRange, typename Function> -auto MakeTransformRange(BaseRange& range, Function f) { +auto MakeTransformRange(BaseRange&& range, Function f) { return MakeIterationRange(MakeTransformIterator(range.begin(), f), MakeTransformIterator(range.end(), f)); } diff --git a/runtime/entrypoints/entrypoint_utils-inl.h b/runtime/entrypoints/entrypoint_utils-inl.h index 847cbfb588..e2aa81f837 100644 --- a/runtime/entrypoints/entrypoint_utils-inl.h +++ b/runtime/entrypoints/entrypoint_utils-inl.h @@ -34,7 +34,6 @@ #include "imt_conflict_table.h" #include "imtable-inl.h" #include "indirect_reference_table.h" -#include "jni/jni_internal.h" #include "mirror/array-alloc-inl.h" #include "mirror/class-alloc-inl.h" #include "mirror/class-inl.h" @@ -122,7 +121,7 @@ inline ArtMethod* GetResolvedMethod(ArtMethod* outer_method, uint32_t method_index = code_info.GetMethodIndexOf(inline_info); if (inline_info.GetDexPc() == static_cast<uint32_t>(-1)) { // "charAt" special case. It is the only non-leaf method we inline across dex files. - ArtMethod* inlined_method = jni::DecodeArtMethod(WellKnownClasses::java_lang_String_charAt); + ArtMethod* inlined_method = WellKnownClasses::java_lang_String_charAt; DCHECK_EQ(inlined_method->GetDexMethodIndex(), method_index); return inlined_method; } diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc index ee339a2155..9cb8a93e1f 100644 --- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc @@ -1098,7 +1098,7 @@ extern "C" TwoWordReturn artInstrumentationMethodExitFromCode(Thread* self, static std::string DumpInstruction(ArtMethod* method, uint32_t dex_pc) REQUIRES_SHARED(Locks::mutator_lock_) { if (dex_pc == static_cast<uint32_t>(-1)) { - CHECK(method == jni::DecodeArtMethod(WellKnownClasses::java_lang_String_charAt)); + CHECK(method == WellKnownClasses::java_lang_String_charAt); return "<native>"; } else { CodeItemInstructionAccessor accessor = method->DexInstructions(); @@ -1176,7 +1176,7 @@ static void DumpB74410240DebugData(ArtMethod** sp) REQUIRES_SHARED(Locks::mutato if (dex_pc == static_cast<uint32_t>(-1)) { tag = "special "; CHECK(inline_info.Equals(inline_infos.back())); - caller = jni::DecodeArtMethod(WellKnownClasses::java_lang_String_charAt); + caller = WellKnownClasses::java_lang_String_charAt; CHECK_EQ(caller->GetDexMethodIndex(), method_index); } else { ObjPtr<mirror::DexCache> dex_cache = caller->GetDexCache(); diff --git a/runtime/native/dalvik_system_BaseDexClassLoader.cc b/runtime/native/dalvik_system_BaseDexClassLoader.cc index 607395d308..5c127d089c 100644 --- a/runtime/native/dalvik_system_BaseDexClassLoader.cc +++ b/runtime/native/dalvik_system_BaseDexClassLoader.cc @@ -19,43 +19,53 @@ #include <memory> #include "class_loader_context.h" +#include "class_root-inl.h" +#include "mirror/object_array-alloc-inl.h" #include "native_util.h" #include "nativehelper/jni_macros.h" -#include "well_known_classes.h" namespace art { -static bool append_string(JNIEnv* env, jobjectArray array, uint32_t& i, const std::string& string) { - ScopedLocalRef<jstring> jstring(env, env->NewStringUTF(string.c_str())); - if (jstring.get() == nullptr) { - DCHECK(env->ExceptionCheck()); +static bool append_string(Thread* self, + Handle<mirror::ObjectArray<mirror::String>> array, + uint32_t& i, + const std::string& string) REQUIRES_SHARED(Locks::mutator_lock_) { + ObjPtr<mirror::String> ostring = mirror::String::AllocFromModifiedUtf8(self, string.c_str()); + if (ostring == nullptr) { + DCHECK(self->IsExceptionPending()); return false; } - env->SetObjectArrayElement(array, i++, jstring.get()); + // We're initializing a newly allocated array object, so we do not need to record that under + // a transaction. If the transaction is aborted, the whole object shall be unreachable. + array->SetWithoutChecks</*kTransactionActive=*/ false, /*kCheckTransaction=*/ false>(i, ostring); + ++i; return true; } static jobjectArray BaseDexClassLoader_computeClassLoaderContextsNative(JNIEnv* env, jobject class_loader) { CHECK(class_loader != nullptr); - std::map<std::string, std::string> contextMap = + std::map<std::string, std::string> context_map = ClassLoaderContext::EncodeClassPathContextsForClassLoader(class_loader); - jobjectArray result = env->NewObjectArray(2 * contextMap.size(), - WellKnownClasses::java_lang_String, - nullptr); - if (result == nullptr) { - DCHECK(env->ExceptionCheck()); + Thread* self = down_cast<JNIEnvExt*>(env)->GetSelf(); + ScopedObjectAccess soa(self); + StackHandleScope<1u> hs(self); + Handle<mirror::ObjectArray<mirror::String>> array = hs.NewHandle( + mirror::ObjectArray<mirror::String>::Alloc( + self, GetClassRoot<mirror::ObjectArray<mirror::String>>(), 2 * context_map.size())); + if (array == nullptr) { + DCHECK(self->IsExceptionPending()); return nullptr; } uint32_t i = 0; - for (const auto& classpath_to_context : contextMap) { + for (const auto& classpath_to_context : context_map) { const std::string& classpath = classpath_to_context.first; const std::string& context = classpath_to_context.second; - if (!append_string(env, result, i, classpath) || !append_string(env, result, i, context)) { + if (!append_string(self, array, i, classpath) || !append_string(self, array, i, context)) { return nullptr; } } - return result; + return soa.AddLocalReference<jobjectArray>(array.Get()); } static JNINativeMethod gMethods[] = { diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc index a9f380dfd5..21e7f777cb 100644 --- a/runtime/native/dalvik_system_DexFile.cc +++ b/runtime/native/dalvik_system_DexFile.cc @@ -28,6 +28,7 @@ #include "base/logging.h" #include "base/os.h" #include "base/stl_util.h" +#include "base/transform_iterator.h" #include "base/utils.h" #include "base/zip_archive.h" #include "class_linker.h" @@ -53,7 +54,7 @@ #include "oat_file_manager.h" #include "runtime.h" #include "scoped_thread_state_change-inl.h" -#include "well_known_classes.h" +#include "string_array_utils.h" namespace art { @@ -508,23 +509,12 @@ static jobjectArray DexFile_getClassNameList(JNIEnv* env, jclass, jobject cookie } // Now create output array and copy the set into it. - jobjectArray result = env->NewObjectArray(descriptors.size(), - WellKnownClasses::java_lang_String, - nullptr); - if (result != nullptr) { - auto it = descriptors.begin(); - auto it_end = descriptors.end(); - jsize i = 0; - for (; it != it_end; it++, ++i) { - std::string descriptor(DescriptorToDot(*it)); - ScopedLocalRef<jstring> jdescriptor(env, env->NewStringUTF(descriptor.c_str())); - if (jdescriptor.get() == nullptr) { - return nullptr; - } - env->SetObjectArrayElement(result, i, jdescriptor.get()); - } - } - return result; + ScopedObjectAccess soa(down_cast<JNIEnvExt*>(env)->GetSelf()); + auto descriptor_to_dot = [](const char* descriptor) { return DescriptorToDot(descriptor); }; + return soa.AddLocalReference<jobjectArray>(CreateStringArray( + soa.Self(), + descriptors.size(), + MakeTransformRange(descriptors, descriptor_to_dot))); } static jint GetDexOptNeeded(JNIEnv* env, @@ -655,23 +645,11 @@ static jobjectArray DexFile_getDexFileOptimizationStatus(JNIEnv* env, OatFileAssistant::GetOptimizationStatus( filename.c_str(), target_instruction_set, &compilation_filter, &compilation_reason); - ScopedLocalRef<jstring> j_compilation_filter(env, env->NewStringUTF(compilation_filter.c_str())); - if (j_compilation_filter.get() == nullptr) { - return nullptr; - } - ScopedLocalRef<jstring> j_compilation_reason(env, env->NewStringUTF(compilation_reason.c_str())); - if (j_compilation_reason.get() == nullptr) { - return nullptr; - } - - // Now create output array and copy the set into it. - jobjectArray result = env->NewObjectArray(2, - WellKnownClasses::java_lang_String, - nullptr); - env->SetObjectArrayElement(result, 0, j_compilation_filter.get()); - env->SetObjectArrayElement(result, 1, j_compilation_reason.get()); - - return result; + ScopedObjectAccess soa(down_cast<JNIEnvExt*>(env)->GetSelf()); + return soa.AddLocalReference<jobjectArray>(CreateStringArray(soa.Self(), { + compilation_filter.c_str(), + compilation_reason.c_str() + })); } static jint DexFile_getDexOptNeeded(JNIEnv* env, @@ -914,31 +892,16 @@ static jobjectArray DexFile_getDexFileOutputPaths(JNIEnv* env, oat_filename = best_oat_file->GetLocation(); is_vdex_only = best_oat_file->IsBackedByVdexOnly(); } - ScopedLocalRef<jstring> joatFilename(env, env->NewStringUTF(oat_filename.c_str())); - if (joatFilename.get() == nullptr) { - return nullptr; - } - if (is_vdex_only) { - jobjectArray result = env->NewObjectArray(1, - WellKnownClasses::java_lang_String, - nullptr); - env->SetObjectArrayElement(result, 0, joatFilename.get()); - return result; - } else { + const char* filenames[] = { oat_filename.c_str(), nullptr }; + ArrayRef<const char* const> used_filenames(filenames, 1u); + if (!is_vdex_only) { vdex_filename = GetVdexFilename(oat_filename); - ScopedLocalRef<jstring> jvdexFilename(env, env->NewStringUTF(vdex_filename.c_str())); - if (jvdexFilename.get() == nullptr) { - return nullptr; - } - - jobjectArray result = env->NewObjectArray(2, - WellKnownClasses::java_lang_String, - nullptr); - env->SetObjectArrayElement(result, 0, jvdexFilename.get()); - env->SetObjectArrayElement(result, 1, joatFilename.get()); - return result; + filenames[1] = vdex_filename.c_str(); + used_filenames = ArrayRef<const char* const>(filenames, 2u); } + ScopedObjectAccess soa(down_cast<JNIEnvExt*>(env)->GetSelf()); + return soa.AddLocalReference<jobjectArray>(CreateStringArray(soa.Self(), used_filenames)); } static jlong DexFile_getStaticSizeOfDexFile(JNIEnv* env, jclass, jobject cookie) { diff --git a/runtime/native/dalvik_system_VMDebug.cc b/runtime/native/dalvik_system_VMDebug.cc index 1d5ac02c8b..2c651df646 100644 --- a/runtime/native/dalvik_system_VMDebug.cc +++ b/runtime/native/dalvik_system_VMDebug.cc @@ -27,6 +27,7 @@ #include "base/histogram-inl.h" #include "base/time_utils.h" #include "class_linker.h" +#include "class_root-inl.h" #include "common_throws.h" #include "debugger.h" #include "gc/space/bump_pointer_space.h" @@ -41,37 +42,26 @@ #include "mirror/array-alloc-inl.h" #include "mirror/array-inl.h" #include "mirror/class.h" -#include "mirror/object_array-inl.h" +#include "mirror/object_array-alloc-inl.h" #include "native_util.h" #include "nativehelper/scoped_local_ref.h" #include "nativehelper/scoped_utf_chars.h" #include "scoped_fast_native_object_access-inl.h" +#include "string_array_utils.h" #include "trace.h" -#include "well_known_classes.h" namespace art { static jobjectArray VMDebug_getVmFeatureList(JNIEnv* env, jclass) { - static const char* features[] = { - "method-trace-profiling", - "method-trace-profiling-streaming", - "method-sample-profiling", - "hprof-heap-dump", - "hprof-heap-dump-streaming", - }; - jobjectArray result = env->NewObjectArray(arraysize(features), - WellKnownClasses::java_lang_String, - nullptr); - if (result != nullptr) { - for (size_t i = 0; i < arraysize(features); ++i) { - ScopedLocalRef<jstring> jfeature(env, env->NewStringUTF(features[i])); - if (jfeature.get() == nullptr) { - return nullptr; - } - env->SetObjectArrayElement(result, i, jfeature.get()); - } - } - return result; + Thread* self = down_cast<JNIEnvExt*>(env)->GetSelf(); + ScopedObjectAccess soa(self); + return soa.AddLocalReference<jobjectArray>(CreateStringArray(self, { + "method-trace-profiling", + "method-trace-profiling-streaming", + "method-sample-profiling", + "hprof-heap-dump", + "hprof-heap-dump-streaming", + })); } static void VMDebug_startAllocCounting(JNIEnv*, jclass) { @@ -373,55 +363,77 @@ static jstring VMDebug_getRuntimeStatInternal(JNIEnv* env, jclass, jint statId) } } -static bool SetRuntimeStatValue(JNIEnv* env, - jobjectArray result, +static bool SetRuntimeStatValue(Thread* self, + Handle<mirror::ObjectArray<mirror::String>> array, VMDebugRuntimeStatId id, - const std::string& value) { - ScopedLocalRef<jstring> jvalue(env, env->NewStringUTF(value.c_str())); - if (jvalue.get() == nullptr) { + const std::string& value) REQUIRES_SHARED(Locks::mutator_lock_) { + ObjPtr<mirror::String> ovalue = mirror::String::AllocFromModifiedUtf8(self, value.c_str()); + if (ovalue == nullptr) { + DCHECK(self->IsExceptionPending()); return false; } - env->SetObjectArrayElement(result, static_cast<jint>(id), jvalue.get()); + // We're initializing a newly allocated array object, so we do not need to record that under + // a transaction. If the transaction is aborted, the whole object shall be unreachable. + array->SetWithoutChecks</*kTransactionActive=*/ false, /*kCheckTransaction=*/ false>( + static_cast<int32_t>(id), ovalue); return true; } static jobjectArray VMDebug_getRuntimeStatsInternal(JNIEnv* env, jclass) { - jobjectArray result = env->NewObjectArray( - static_cast<jint>(VMDebugRuntimeStatId::kNumRuntimeStats), - WellKnownClasses::java_lang_String, - nullptr); - if (result == nullptr) { + Thread* self = down_cast<JNIEnvExt*>(env)->GetSelf(); + ScopedObjectAccess soa(self); + StackHandleScope<1u> hs(self); + int32_t size = enum_cast<int32_t>(VMDebugRuntimeStatId::kNumRuntimeStats); + Handle<mirror::ObjectArray<mirror::String>> array = hs.NewHandle( + mirror::ObjectArray<mirror::String>::Alloc( + self, GetClassRoot<mirror::ObjectArray<mirror::String>>(), size)); + if (array == nullptr) { + DCHECK(self->IsExceptionPending()); return nullptr; } gc::Heap* heap = Runtime::Current()->GetHeap(); - if (!SetRuntimeStatValue(env, result, VMDebugRuntimeStatId::kArtGcGcCount, + if (!SetRuntimeStatValue(self, + array, + VMDebugRuntimeStatId::kArtGcGcCount, std::to_string(heap->GetGcCount()))) { return nullptr; } - if (!SetRuntimeStatValue(env, result, VMDebugRuntimeStatId::kArtGcGcTime, + if (!SetRuntimeStatValue(self, + array, + VMDebugRuntimeStatId::kArtGcGcTime, std::to_string(NsToMs(heap->GetGcTime())))) { return nullptr; } - if (!SetRuntimeStatValue(env, result, VMDebugRuntimeStatId::kArtGcBytesAllocated, + if (!SetRuntimeStatValue(self, + array, + VMDebugRuntimeStatId::kArtGcBytesAllocated, std::to_string(heap->GetBytesAllocatedEver()))) { return nullptr; } - if (!SetRuntimeStatValue(env, result, VMDebugRuntimeStatId::kArtGcBytesFreed, + if (!SetRuntimeStatValue(self, + array, + VMDebugRuntimeStatId::kArtGcBytesFreed, std::to_string(heap->GetBytesFreedEver()))) { return nullptr; } - if (!SetRuntimeStatValue(env, result, VMDebugRuntimeStatId::kArtGcBlockingGcCount, + if (!SetRuntimeStatValue(self, + array, + VMDebugRuntimeStatId::kArtGcBlockingGcCount, std::to_string(heap->GetBlockingGcCount()))) { return nullptr; } - if (!SetRuntimeStatValue(env, result, VMDebugRuntimeStatId::kArtGcBlockingGcTime, + if (!SetRuntimeStatValue(self, + array, + VMDebugRuntimeStatId::kArtGcBlockingGcTime, std::to_string(NsToMs(heap->GetBlockingGcTime())))) { return nullptr; } { std::ostringstream output; heap->DumpGcCountRateHistogram(output); - if (!SetRuntimeStatValue(env, result, VMDebugRuntimeStatId::kArtGcGcCountRateHistogram, + if (!SetRuntimeStatValue(self, + array, + VMDebugRuntimeStatId::kArtGcGcCountRateHistogram, output.str())) { return nullptr; } @@ -429,12 +441,14 @@ static jobjectArray VMDebug_getRuntimeStatsInternal(JNIEnv* env, jclass) { { std::ostringstream output; heap->DumpBlockingGcCountRateHistogram(output); - if (!SetRuntimeStatValue(env, result, VMDebugRuntimeStatId::kArtGcBlockingGcCountRateHistogram, + if (!SetRuntimeStatValue(self, + array, + VMDebugRuntimeStatId::kArtGcBlockingGcCountRateHistogram, output.str())) { return nullptr; } } - return result; + return soa.AddLocalReference<jobjectArray>(array.Get()); } static void VMDebug_nativeAttachAgent(JNIEnv* env, jclass, jstring agent, jobject classloader) { diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc index da5d53a5d9..a88187912c 100644 --- a/runtime/native/dalvik_system_VMRuntime.cc +++ b/runtime/native/dalvik_system_VMRuntime.cc @@ -61,9 +61,9 @@ extern "C" void android_set_application_target_sdk_version(uint32_t version); #include "runtime.h" #include "scoped_fast_native_object_access-inl.h" #include "scoped_thread_state_change-inl.h" +#include "string_array_utils.h" #include "thread.h" #include "thread_list.h" -#include "well_known_classes.h" namespace art { @@ -190,27 +190,9 @@ static jboolean VMRuntime_isJavaDebuggable(JNIEnv*, jobject) { } static jobjectArray VMRuntime_properties(JNIEnv* env, jobject) { - DCHECK(WellKnownClasses::java_lang_String != nullptr); - const std::vector<std::string>& properties = Runtime::Current()->GetProperties(); - ScopedLocalRef<jobjectArray> ret(env, - env->NewObjectArray(static_cast<jsize>(properties.size()), - WellKnownClasses::java_lang_String, - nullptr /* initial element */)); - if (ret == nullptr) { - DCHECK(env->ExceptionCheck()); - return nullptr; - } - for (size_t i = 0; i != properties.size(); ++i) { - ScopedLocalRef<jstring> str(env, env->NewStringUTF(properties[i].c_str())); - if (str == nullptr) { - DCHECK(env->ExceptionCheck()); - return nullptr; - } - env->SetObjectArrayElement(ret.get(), static_cast<jsize>(i), str.get()); - DCHECK(!env->ExceptionCheck()); - } - return ret.release(); + ScopedObjectAccess soa(down_cast<JNIEnvExt*>(env)->GetSelf()); + return soa.AddLocalReference<jobjectArray>(CreateStringArray(soa.Self(), properties)); } // This is for backward compatibility with dalvik which returned the diff --git a/runtime/native/java_lang_VMClassLoader.cc b/runtime/native/java_lang_VMClassLoader.cc index ee40eb1005..b327e51849 100644 --- a/runtime/native/java_lang_VMClassLoader.cc +++ b/runtime/native/java_lang_VMClassLoader.cc @@ -18,7 +18,8 @@ #include "base/zip_archive.h" #include "class_linker.h" -#include "class_root-inl.h" +#include "base/transform_iterator.h" +#include "base/stl_util.h" #include "dex/descriptors_names.h" #include "dex/dex_file_loader.h" #include "dex/utf.h" @@ -33,6 +34,7 @@ #include "nativehelper/scoped_utf_chars.h" #include "obj_ptr.h" #include "scoped_fast_native_object_access-inl.h" +#include "string_array_utils.h" #include "well_known_classes.h" namespace art { @@ -137,46 +139,31 @@ static jobjectArray VMClassLoader_getBootClassPathEntries(JNIEnv* env, jclass) { return !DexFileLoader::IsMultiDexLocation(dex_file->GetLocation().c_str()); }; size_t jar_count = std::count_if(path.begin(), path.end(), is_base_dex); - Thread* self = down_cast<JNIEnvExt*>(env)->GetSelf(); - ScopedObjectAccess soa(self); - StackHandleScope<1u> hs(self); - Handle<mirror::ObjectArray<mirror::String>> array = hs.NewHandle( - mirror::ObjectArray<mirror::String>::Alloc( - self, GetClassRoot<mirror::ObjectArray<mirror::String>>(class_linker), jar_count)); - if (array == nullptr) { - DCHECK(self->IsExceptionPending()); - return nullptr; - } - size_t pos = 0; - for (size_t i = 0, size = path.size(); i != size; ++i) { - const DexFile* dex_file = path[i]; + const DexFile* last_dex_file = nullptr; + auto dchecked_is_base_dex = [&](const DexFile* dex_file) { // For multidex locations, e.g., x.jar!classes2.dex, we want to look into x.jar. // But we do not need to look into the base dex file more than once so we filter // out multidex locations using the fact that they follow the base location. - if (!is_base_dex(dex_file)) { - DCHECK_NE(i, 0u); - DCHECK_EQ(DexFileLoader::GetBaseLocation(dex_file->GetLocation().c_str()), - DexFileLoader::GetBaseLocation(path[i - 1u]->GetLocation().c_str())); - continue; - } - - DCHECK_EQ(DexFileLoader::GetBaseLocation(dex_file->GetLocation().c_str()), - dex_file->GetLocation()); - ObjPtr<mirror::String> java_path = - mirror::String::AllocFromModifiedUtf8(self, dex_file->GetLocation().c_str()); - if (java_path == nullptr) { - DCHECK(self->IsExceptionPending()); - return nullptr; + if (kIsDebugBuild) { + if (is_base_dex(dex_file)) { + CHECK_EQ(DexFileLoader::GetBaseLocation(dex_file->GetLocation().c_str()), + dex_file->GetLocation()); + } else { + CHECK(last_dex_file != nullptr); + CHECK_EQ(DexFileLoader::GetBaseLocation(dex_file->GetLocation().c_str()), + DexFileLoader::GetBaseLocation(last_dex_file->GetLocation().c_str())); + } + last_dex_file = dex_file; } - // We're initializing a newly allocated array object, so we do not need to record that under - // a transaction. If the transaction is aborted, the whole object shall be unreachable. - array->SetWithoutChecks</*kTransactionActive=*/ false, /*kCheckTransaction=*/ false>( - pos, java_path); - ++pos; - } - DCHECK_EQ(pos, jar_count); - return soa.AddLocalReference<jobjectArray>(array.Get()); + return is_base_dex(dex_file); + }; + auto get_location = [](const DexFile* dex_file) { return dex_file->GetLocation(); }; + ScopedObjectAccess soa(down_cast<JNIEnvExt*>(env)->GetSelf()); + return soa.AddLocalReference<jobjectArray>(CreateStringArray( + soa.Self(), + jar_count, + MakeTransformRange(Filter(path, dchecked_is_base_dex), get_location))); } static JNINativeMethod gMethods[] = { diff --git a/runtime/native/java_lang_reflect_Constructor.cc b/runtime/native/java_lang_reflect_Constructor.cc index 1d362c0302..4b2cc43ed3 100644 --- a/runtime/native/java_lang_reflect_Constructor.cc +++ b/runtime/native/java_lang_reflect_Constructor.cc @@ -33,7 +33,6 @@ #include "native_util.h" #include "reflection.h" #include "scoped_fast_native_object_access-inl.h" -#include "well_known_classes.h" namespace art { diff --git a/runtime/native/java_lang_reflect_Method.cc b/runtime/native/java_lang_reflect_Method.cc index 706f1a61ba..5f02ad0fd9 100644 --- a/runtime/native/java_lang_reflect_Method.cc +++ b/runtime/native/java_lang_reflect_Method.cc @@ -31,7 +31,6 @@ #include "native_util.h" #include "reflection.h" #include "scoped_fast_native_object_access-inl.h" -#include "well_known_classes.h" namespace art { diff --git a/runtime/native/string_array_utils.h b/runtime/native/string_array_utils.h new file mode 100644 index 0000000000..41d50933f9 --- /dev/null +++ b/runtime/native/string_array_utils.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_RUNTIME_NATIVE_STRING_ARRAY_UTILS_H_ +#define ART_RUNTIME_NATIVE_STRING_ARRAY_UTILS_H_ + +#include "base/locks.h" +#include "class_root-inl.h" +#include "handle_scope-inl.h" +#include "mirror/object_array-alloc-inl.h" +#include "mirror/string.h" + +namespace art { + +namespace detail { + +inline const char* GetStringCStr(const char* str) { return str; } +inline const char* GetStringCStr(const std::string& str) { return str.c_str(); } + +} // namespace detail + +template <typename Container> +ObjPtr<mirror::ObjectArray<mirror::String>> CreateStringArray( + Thread* self, size_t size, const Container& entries) REQUIRES_SHARED(Locks::mutator_lock_) { + StackHandleScope<1u> hs(self); + Handle<mirror::ObjectArray<mirror::String>> array = hs.NewHandle( + mirror::ObjectArray<mirror::String>::Alloc( + self, GetClassRoot<mirror::ObjectArray<mirror::String>>(), size)); + if (array == nullptr) { + DCHECK(self->IsExceptionPending()); + return nullptr; + } + // Note: If the container's iterator returns a `std::string` by value, the `auto&&` + // binds as a const reference and extends the lifetime of the temporary object. + size_t pos = 0u; + for (auto&& entry : entries) { + ObjPtr<mirror::String> oentry = + mirror::String::AllocFromModifiedUtf8(self, detail::GetStringCStr(entry)); + if (oentry == nullptr) { + DCHECK(self->IsExceptionPending()); + return nullptr; + } + // We're initializing a newly allocated array object, so we do not need to record that under + // a transaction. If the transaction is aborted, the whole object shall be unreachable. + DCHECK_LT(pos, size); + array->SetWithoutChecks</*kTransactionActive=*/ false, /*kCheckTransaction=*/ false>( + pos, oentry); + ++pos; + } + DCHECK_EQ(pos, size); + return array.Get(); +} + +template <typename Container> +ObjPtr<mirror::ObjectArray<mirror::String>> CreateStringArray( + Thread* self, const Container& entries) REQUIRES_SHARED(Locks::mutator_lock_) { + return CreateStringArray(self, entries.size(), entries); +} + +inline ObjPtr<mirror::ObjectArray<mirror::String>> CreateStringArray( + Thread* self, std::initializer_list<const char*> entries) + REQUIRES_SHARED(Locks::mutator_lock_) { + return CreateStringArray<std::initializer_list<const char*>>(self, entries); +} + +} // namespace art + +#endif // ART_RUNTIME_NATIVE_STRING_ARRAY_UTILS_H_ diff --git a/runtime/reference_table_test.cc b/runtime/reference_table_test.cc index 5fc01abadb..420543eb93 100644 --- a/runtime/reference_table_test.cc +++ b/runtime/reference_table_test.cc @@ -22,6 +22,7 @@ #include "art_method-inl.h" #include "class_linker.h" +#include "class_root-inl.h" #include "common_runtime_test.h" #include "dex/primitive.h" #include "handle_scope-inl.h" @@ -34,7 +35,6 @@ #include "runtime.h" #include "scoped_thread_state_change-inl.h" #include "thread-current-inl.h" -#include "well_known_classes.h" namespace art { @@ -199,18 +199,12 @@ TEST_F(ReferenceTableTest, Basics) { // avoids having to create the low-level args array ourselves. Handle<mirror::Object> h_with_trace; { - jmethodID substr = soa.Env()->GetMethodID(WellKnownClasses::java_lang_String, - "substring", - "(II)Ljava/lang/String;"); + ArtMethod* substr = GetClassRoot<mirror::String>()->FindClassMethod( + "substring", "(II)Ljava/lang/String;", kRuntimePointerSize); ASSERT_TRUE(substr != nullptr); - jobject jobj = soa.Env()->AddLocalReference<jobject>(h_without_trace.Get()); - ASSERT_TRUE(jobj != nullptr); - jobject result = soa.Env()->CallObjectMethod(jobj, - substr, - static_cast<jint>(0), - static_cast<jint>(4)); - ASSERT_TRUE(result != nullptr); - h_with_trace = hs.NewHandle(soa.Self()->DecodeJObject(result)); + h_with_trace = hs.NewHandle( + substr->InvokeFinal<'L', 'I', 'I'>(soa.Self(), h_without_trace.Get(), 0, 4)); + ASSERT_TRUE(h_with_trace != nullptr); } Handle<mirror::Object> h_ref; diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc index 4322a614af..6f994316fc 100644 --- a/runtime/well_known_classes.cc +++ b/runtime/well_known_classes.cc @@ -26,6 +26,7 @@ #include "art_method-inl.h" #include "base/enums.h" #include "class_linker.h" +#include "class_root-inl.h" #include "entrypoints/quick/quick_entrypoints_enum.h" #include "entrypoints/runtime_asm_entrypoints.h" #include "handle_scope-inl.h" @@ -62,7 +63,6 @@ jclass WellKnownClasses::java_lang_reflect_Parameter__array; jclass WellKnownClasses::java_lang_reflect_Proxy; jclass WellKnownClasses::java_lang_RuntimeException; jclass WellKnownClasses::java_lang_StackOverflowError; -jclass WellKnownClasses::java_lang_String; jclass WellKnownClasses::java_lang_StringFactory; jclass WellKnownClasses::java_lang_System; jclass WellKnownClasses::java_lang_Void; @@ -101,7 +101,7 @@ jmethodID WellKnownClasses::java_lang_reflect_Proxy_init; jmethodID WellKnownClasses::java_lang_reflect_Proxy_invoke; jmethodID WellKnownClasses::java_lang_Runtime_nativeLoad; ArtMethod* WellKnownClasses::java_lang_Short_valueOf; -jmethodID WellKnownClasses::java_lang_String_charAt; +ArtMethod* WellKnownClasses::java_lang_String_charAt; ArtMethod* WellKnownClasses::java_lang_Thread_dispatchUncaughtException; ArtMethod* WellKnownClasses::java_lang_Thread_init; ArtMethod* WellKnownClasses::java_lang_Thread_run; @@ -369,7 +369,6 @@ void WellKnownClasses::Init(JNIEnv* env) { java_lang_reflect_Proxy = CacheClass(env, "java/lang/reflect/Proxy"); java_lang_RuntimeException = CacheClass(env, "java/lang/RuntimeException"); java_lang_StackOverflowError = CacheClass(env, "java/lang/StackOverflowError"); - java_lang_String = CacheClass(env, "java/lang/String"); java_lang_StringFactory = CacheClass(env, "java/lang/StringFactory"); java_lang_System = CacheClass(env, "java/lang/System"); java_lang_Void = CacheClass(env, "java/lang/Void"); @@ -412,9 +411,8 @@ void WellKnownClasses::InitFieldsAndMethodsOnly(JNIEnv* env) { java_lang_reflect_InvocationTargetException_init = CacheMethod(env, java_lang_reflect_InvocationTargetException, false, "<init>", "(Ljava/lang/Throwable;)V"); java_lang_reflect_Parameter_init = CacheMethod(env, java_lang_reflect_Parameter, false, "<init>", "(Ljava/lang/String;ILjava/lang/reflect/Executable;I)V"); - java_lang_String_charAt = CacheMethod(env, java_lang_String, false, "charAt", "(I)C"); - StackHandleScope<29u> hs(self); + StackHandleScope<28u> hs(self); Handle<mirror::Class> d_s_bdcl = hs.NewHandle(FindSystemClass(class_linker, self, "Ldalvik/system/BaseDexClassLoader;")); Handle<mirror::Class> d_s_dlcl = @@ -445,8 +443,6 @@ void WellKnownClasses::InitFieldsAndMethodsOnly(JNIEnv* env) { hs.NewHandle(FindSystemClass(class_linker, self, "Ljava/lang/Thread;")); Handle<mirror::Class> j_l_tg = hs.NewHandle(FindSystemClass(class_linker, self, "Ljava/lang/ThreadGroup;")); - Handle<mirror::Class> j_l_Throwable = - hs.NewHandle(FindSystemClass(class_linker, self, "Ljava/lang/Throwable;")); Handle<mirror::Class> j_l_i_MethodHandle = hs.NewHandle(FindSystemClass(class_linker, self, "Ljava/lang/invoke/MethodHandle;")); Handle<mirror::Class> j_l_i_MethodHandles = @@ -538,6 +534,10 @@ void WellKnownClasses::InitFieldsAndMethodsOnly(JNIEnv* env) { java_lang_Float_floatToRawIntBits = CacheMethod(j_l_Float, /*is_static=*/ true, "floatToRawIntBits", "(F)I", pointer_size); + ObjPtr<mirror::Class> j_l_String = GetClassRoot<mirror::String>(class_linker); + java_lang_String_charAt = CacheMethod( + j_l_String, /*is_static=*/ false, "charAt", "(I)C", pointer_size); + java_lang_Thread_dispatchUncaughtException = CacheMethod( j_l_Thread.Get(), /*is_static=*/ false, @@ -675,16 +675,17 @@ void WellKnownClasses::InitFieldsAndMethodsOnly(JNIEnv* env) { java_lang_ThreadGroup_systemThreadGroup = CacheField(j_l_tg.Get(), /*is_static=*/ true, "systemThreadGroup", "Ljava/lang/ThreadGroup;"); + ObjPtr<mirror::Class> j_l_Throwable = GetClassRoot<mirror::Throwable>(class_linker); java_lang_Throwable_cause = CacheField( - j_l_Throwable.Get(), /*is_static=*/ false, "cause", "Ljava/lang/Throwable;"); + j_l_Throwable, /*is_static=*/ false, "cause", "Ljava/lang/Throwable;"); java_lang_Throwable_detailMessage = CacheField( - j_l_Throwable.Get(), /*is_static=*/ false, "detailMessage", "Ljava/lang/String;"); + j_l_Throwable, /*is_static=*/ false, "detailMessage", "Ljava/lang/String;"); java_lang_Throwable_stackTrace = CacheField( - j_l_Throwable.Get(), /*is_static=*/ false, "stackTrace", "[Ljava/lang/StackTraceElement;"); + j_l_Throwable, /*is_static=*/ false, "stackTrace", "[Ljava/lang/StackTraceElement;"); java_lang_Throwable_stackState = CacheField( - j_l_Throwable.Get(), /*is_static=*/ false, "backtrace", "Ljava/lang/Object;"); + j_l_Throwable, /*is_static=*/ false, "backtrace", "Ljava/lang/Object;"); java_lang_Throwable_suppressedExceptions = CacheField( - j_l_Throwable.Get(), /*is_static=*/ false, "suppressedExceptions", "Ljava/util/List;"); + j_l_Throwable, /*is_static=*/ false, "suppressedExceptions", "Ljava/util/List;"); java_nio_Buffer_address = CacheField(j_n_b.Get(), /*is_static=*/ false, "address", "J"); java_nio_Buffer_capacity = CacheField(j_n_b.Get(), /*is_static=*/ false, "capacity", "I"); @@ -761,7 +762,6 @@ void WellKnownClasses::Clear() { java_lang_reflect_Proxy = nullptr; java_lang_RuntimeException = nullptr; java_lang_StackOverflowError = nullptr; - java_lang_String = nullptr; java_lang_StringFactory = nullptr; java_lang_System = nullptr; java_lang_Void = nullptr; diff --git a/runtime/well_known_classes.h b/runtime/well_known_classes.h index 1a07d9ccd4..f3da722f9e 100644 --- a/runtime/well_known_classes.h +++ b/runtime/well_known_classes.h @@ -108,7 +108,6 @@ struct WellKnownClasses { static jclass java_lang_reflect_Proxy; static jclass java_lang_RuntimeException; static jclass java_lang_StackOverflowError; - static jclass java_lang_String; static jclass java_lang_StringFactory; static jclass java_lang_System; static jclass java_lang_Void; @@ -147,7 +146,7 @@ struct WellKnownClasses { static jmethodID java_lang_reflect_Proxy_invoke; static jmethodID java_lang_Runtime_nativeLoad; static ArtMethod* java_lang_Short_valueOf; - static jmethodID java_lang_String_charAt; + static ArtMethod* java_lang_String_charAt; static ArtMethod* java_lang_Thread_dispatchUncaughtException; static ArtMethod* java_lang_Thread_init; static ArtMethod* java_lang_Thread_run; @@ -225,7 +224,6 @@ struct WellKnownClasses { static constexpr ClassFromField<&java_lang_ClassLoader_parent> java_lang_ClassLoader; static constexpr ClassFromField<&java_lang_Thread_daemon> java_lang_Thread; static constexpr ClassFromField<&java_lang_ThreadGroup_groups> java_lang_ThreadGroup; - static constexpr ClassFromField<&java_lang_Throwable_cause> java_lang_Throwable; static constexpr ClassFromField<&java_nio_Buffer_address> java_nio_Buffer; static constexpr ClassFromField<&java_util_Collections_EMPTY_LIST> java_util_Collections; static constexpr ClassFromField<&libcore_util_EmptyArray_STACK_TRACE_ELEMENT> |