summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Vladimir Marko <vmarko@google.com> 2022-11-29 10:30:42 +0000
committer Vladimir Marko <vmarko@google.com> 2022-11-30 15:38:00 +0000
commit97de32773e20297125d4e35e5d7dcb3b6732e063 (patch)
tree0d1f79ef1a8b7f82f0b3d70311d0b2ed85707244
parent0110e952e488bc41429f6f33f36e8884f41a26d8 (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.cc2
-rw-r--r--libartbase/base/stl_util.h9
-rw-r--r--libartbase/base/transform_iterator.h2
-rw-r--r--runtime/entrypoints/entrypoint_utils-inl.h3
-rw-r--r--runtime/entrypoints/quick/quick_trampoline_entrypoints.cc4
-rw-r--r--runtime/native/dalvik_system_BaseDexClassLoader.cc40
-rw-r--r--runtime/native/dalvik_system_DexFile.cc77
-rw-r--r--runtime/native/dalvik_system_VMDebug.cc98
-rw-r--r--runtime/native/dalvik_system_VMRuntime.cc24
-rw-r--r--runtime/native/java_lang_VMClassLoader.cc59
-rw-r--r--runtime/native/java_lang_reflect_Constructor.cc1
-rw-r--r--runtime/native/java_lang_reflect_Method.cc1
-rw-r--r--runtime/native/string_array_utils.h81
-rw-r--r--runtime/reference_table_test.cc18
-rw-r--r--runtime/well_known_classes.cc26
-rw-r--r--runtime/well_known_classes.h4
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>