summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/common_compiler_test.cc2
-rw-r--r--compiler/driver/compiler_driver.cc2
-rw-r--r--compiler/optimizing/instruction_simplifier.cc16
-rw-r--r--compiler/optimizing/intrinsics.h1
-rw-r--r--compiler/optimizing/intrinsics_arm64.cc7
-rw-r--r--compiler/optimizing/intrinsics_arm_vixl.cc7
-rw-r--r--compiler/optimizing/intrinsics_mips.cc7
-rw-r--r--compiler/optimizing/intrinsics_mips64.cc7
-rw-r--r--compiler/optimizing/intrinsics_x86.cc7
-rw-r--r--compiler/optimizing/intrinsics_x86_64.cc7
-rw-r--r--dexlayout/dex_ir.h2
-rw-r--r--dexlayout/dex_ir_builder.cc2
-rw-r--r--imgdiag/imgdiag.cc5
-rw-r--r--libartbase/base/utils.cc44
-rw-r--r--libartbase/base/utils.h42
-rw-r--r--oatdump/oatdump.cc3
-rw-r--r--patchoat/patchoat.cc5
-rw-r--r--runtime/art_method-inl.h1
-rw-r--r--runtime/class_linker.cc89
-rw-r--r--runtime/class_linker.h26
-rw-r--r--runtime/class_loader_context.cc4
-rw-r--r--runtime/gc/collector/concurrent_copying.cc9
-rw-r--r--runtime/gc/heap.cc5
-rw-r--r--runtime/jit/jit_code_cache.cc23
-rw-r--r--test/004-StackWalk/build6
-rw-r--r--test/004-StackWalk/classes.dexbin3912 -> 3844 bytes
-rw-r--r--test/004-StackWalk/src/Main.java42
-rw-r--r--test/004-StackWalk/stack_walk_jni.cc44
-rw-r--r--test/669-moveable-string-class-equals/expected.txt1
-rw-r--r--test/669-moveable-string-class-equals/info.txt2
-rwxr-xr-xtest/669-moveable-string-class-equals/run19
-rw-r--r--test/669-moveable-string-class-equals/src/Main.java82
-rw-r--r--test/StackWalk2/StackWalk2.java58
-rw-r--r--test/common/runtime_state.cc9
-rw-r--r--test/knownfailures.json4
-rw-r--r--tools/field-null-percent/fieldnull.cc2
-rw-r--r--tools/libcore_gcstress_failures.txt1
37 files changed, 253 insertions, 340 deletions
diff --git a/compiler/common_compiler_test.cc b/compiler/common_compiler_test.cc
index d603d9673c..586891a3ff 100644
--- a/compiler/common_compiler_test.cc
+++ b/compiler/common_compiler_test.cc
@@ -108,7 +108,7 @@ void CommonCompilerTest::MakeExecutable(const void* code_start, size_t code_leng
int result = mprotect(reinterpret_cast<void*>(base), len, PROT_READ | PROT_WRITE | PROT_EXEC);
CHECK_EQ(result, 0);
- FlushInstructionCache(reinterpret_cast<char*>(base), reinterpret_cast<char*>(base + len));
+ FlushInstructionCache(reinterpret_cast<void*>(base), reinterpret_cast<void*>(base + len));
}
void CommonCompilerTest::MakeExecutable(ObjPtr<mirror::ClassLoader> class_loader,
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index f6afe2c958..95d08b3c64 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -2564,8 +2564,8 @@ static void CompileDexFile(CompilerDriver* driver,
thread_pool);
auto compile = [&context, &compile_fn](size_t class_def_index) {
- ScopedTrace trace(__FUNCTION__);
const DexFile& dex_file = *context.GetDexFile();
+ SCOPED_TRACE << "compile " << dex_file.GetLocation() << "@" << class_def_index;
ClassLinker* class_linker = context.GetClassLinker();
jobject jclass_loader = context.GetClassLoader();
ClassReference ref(&dex_file, class_def_index);
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index 2757f7b719..bb96c211cb 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -2146,22 +2146,6 @@ void InstructionSimplifierVisitor::SimplifyStringEquals(HInvoke* instruction) {
ReferenceTypeInfo argument_rti = argument->GetReferenceTypeInfo();
if (argument_rti.IsValid() && argument_rti.IsStringClass()) {
optimizations.SetArgumentIsString();
- } else if (kUseReadBarrier) {
- DCHECK(instruction->GetResolvedMethod() != nullptr);
- DCHECK(instruction->GetResolvedMethod()->GetDeclaringClass()->IsStringClass() ||
- // Object.equals() can be devirtualized to String.equals().
- instruction->GetResolvedMethod()->GetDeclaringClass()->IsObjectClass());
- Runtime* runtime = Runtime::Current();
- // For AOT, we always assume that the boot image shall contain the String.class and
- // we do not need a read barrier for boot image classes as they are non-moveable.
- // For JIT, check if we actually have a boot image; if we do, the String.class
- // should also be non-moveable.
- if (runtime->IsAotCompiler() || runtime->GetHeap()->HasBootImageSpace()) {
- DCHECK(runtime->IsAotCompiler() ||
- !runtime->GetHeap()->IsMovableObject(
- instruction->GetResolvedMethod()->GetDeclaringClass()));
- optimizations.SetNoReadBarrierForStringClass();
- }
}
}
}
diff --git a/compiler/optimizing/intrinsics.h b/compiler/optimizing/intrinsics.h
index 06e2fbb355..2d93f234be 100644
--- a/compiler/optimizing/intrinsics.h
+++ b/compiler/optimizing/intrinsics.h
@@ -219,7 +219,6 @@ class StringEqualsOptimizations : public IntrinsicOptimizations {
INTRINSIC_OPTIMIZATION(ArgumentNotNull, 0);
INTRINSIC_OPTIMIZATION(ArgumentIsString, 1);
- INTRINSIC_OPTIMIZATION(NoReadBarrierForStringClass, 2);
private:
DISALLOW_COPY_AND_ASSIGN(StringEqualsOptimizations);
diff --git a/compiler/optimizing/intrinsics_arm64.cc b/compiler/optimizing/intrinsics_arm64.cc
index 1abfcb022b..7684dc79f2 100644
--- a/compiler/optimizing/intrinsics_arm64.cc
+++ b/compiler/optimizing/intrinsics_arm64.cc
@@ -1398,13 +1398,6 @@ static const char* GetConstString(HInstruction* candidate, uint32_t* utf16_lengt
}
void IntrinsicLocationsBuilderARM64::VisitStringEquals(HInvoke* invoke) {
- if (kEmitCompilerReadBarrier &&
- !StringEqualsOptimizations(invoke).GetArgumentIsString() &&
- !StringEqualsOptimizations(invoke).GetNoReadBarrierForStringClass()) {
- // No support for this odd case (String class is moveable, not in the boot image).
- return;
- }
-
LocationSummary* locations =
new (allocator_) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
locations->SetInAt(0, Location::RequiresRegister());
diff --git a/compiler/optimizing/intrinsics_arm_vixl.cc b/compiler/optimizing/intrinsics_arm_vixl.cc
index 1127fb8191..bc59fcf50c 100644
--- a/compiler/optimizing/intrinsics_arm_vixl.cc
+++ b/compiler/optimizing/intrinsics_arm_vixl.cc
@@ -1458,13 +1458,6 @@ static const char* GetConstString(HInstruction* candidate, uint32_t* utf16_lengt
}
void IntrinsicLocationsBuilderARMVIXL::VisitStringEquals(HInvoke* invoke) {
- if (kEmitCompilerReadBarrier &&
- !StringEqualsOptimizations(invoke).GetArgumentIsString() &&
- !StringEqualsOptimizations(invoke).GetNoReadBarrierForStringClass()) {
- // No support for this odd case (String class is moveable, not in the boot image).
- return;
- }
-
LocationSummary* locations =
new (allocator_) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
InvokeRuntimeCallingConventionARMVIXL calling_convention;
diff --git a/compiler/optimizing/intrinsics_mips.cc b/compiler/optimizing/intrinsics_mips.cc
index 771714bf41..6f7f5e49c1 100644
--- a/compiler/optimizing/intrinsics_mips.cc
+++ b/compiler/optimizing/intrinsics_mips.cc
@@ -1516,13 +1516,6 @@ void IntrinsicCodeGeneratorMIPS::VisitStringCompareTo(HInvoke* invoke) {
// boolean java.lang.String.equals(Object anObject)
void IntrinsicLocationsBuilderMIPS::VisitStringEquals(HInvoke* invoke) {
- if (kEmitCompilerReadBarrier &&
- !StringEqualsOptimizations(invoke).GetArgumentIsString() &&
- !StringEqualsOptimizations(invoke).GetNoReadBarrierForStringClass()) {
- // No support for this odd case (String class is moveable, not in the boot image).
- return;
- }
-
LocationSummary* locations =
new (allocator_) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
locations->SetInAt(0, Location::RequiresRegister());
diff --git a/compiler/optimizing/intrinsics_mips64.cc b/compiler/optimizing/intrinsics_mips64.cc
index 4a1bd5b7b2..2eb252908c 100644
--- a/compiler/optimizing/intrinsics_mips64.cc
+++ b/compiler/optimizing/intrinsics_mips64.cc
@@ -1369,13 +1369,6 @@ void IntrinsicCodeGeneratorMIPS64::VisitStringCompareTo(HInvoke* invoke) {
// boolean java.lang.String.equals(Object anObject)
void IntrinsicLocationsBuilderMIPS64::VisitStringEquals(HInvoke* invoke) {
- if (kEmitCompilerReadBarrier &&
- !StringEqualsOptimizations(invoke).GetArgumentIsString() &&
- !StringEqualsOptimizations(invoke).GetNoReadBarrierForStringClass()) {
- // No support for this odd case (String class is moveable, not in the boot image).
- return;
- }
-
LocationSummary* locations =
new (allocator_) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
locations->SetInAt(0, Location::RequiresRegister());
diff --git a/compiler/optimizing/intrinsics_x86.cc b/compiler/optimizing/intrinsics_x86.cc
index d33c0c344e..3504d7a6f8 100644
--- a/compiler/optimizing/intrinsics_x86.cc
+++ b/compiler/optimizing/intrinsics_x86.cc
@@ -922,13 +922,6 @@ void IntrinsicCodeGeneratorX86::VisitStringCompareTo(HInvoke* invoke) {
}
void IntrinsicLocationsBuilderX86::VisitStringEquals(HInvoke* invoke) {
- if (kEmitCompilerReadBarrier &&
- !StringEqualsOptimizations(invoke).GetArgumentIsString() &&
- !StringEqualsOptimizations(invoke).GetNoReadBarrierForStringClass()) {
- // No support for this odd case (String class is moveable, not in the boot image).
- return;
- }
-
LocationSummary* locations =
new (allocator_) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
locations->SetInAt(0, Location::RequiresRegister());
diff --git a/compiler/optimizing/intrinsics_x86_64.cc b/compiler/optimizing/intrinsics_x86_64.cc
index ae889744ad..96f6eaaf33 100644
--- a/compiler/optimizing/intrinsics_x86_64.cc
+++ b/compiler/optimizing/intrinsics_x86_64.cc
@@ -1230,13 +1230,6 @@ void IntrinsicCodeGeneratorX86_64::VisitStringCompareTo(HInvoke* invoke) {
}
void IntrinsicLocationsBuilderX86_64::VisitStringEquals(HInvoke* invoke) {
- if (kEmitCompilerReadBarrier &&
- !StringEqualsOptimizations(invoke).GetArgumentIsString() &&
- !StringEqualsOptimizations(invoke).GetNoReadBarrierForStringClass()) {
- // No support for this odd case (String class is moveable, not in the boot image).
- return;
- }
-
LocationSummary* locations =
new (allocator_) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
locations->SetInAt(0, Location::RequiresRegister());
diff --git a/dexlayout/dex_ir.h b/dexlayout/dex_ir.h
index 178a4d4df1..598f7df778 100644
--- a/dexlayout/dex_ir.h
+++ b/dexlayout/dex_ir.h
@@ -215,7 +215,7 @@ class CollectionBase {
uint32_t GetOffset() const { return offset_; }
void SetOffset(uint32_t new_offset) { offset_ = new_offset; }
- virtual uint32_t Size() const { return 0U; }
+ virtual uint32_t Size() const = 0;
private:
// Start out unassigned.
diff --git a/dexlayout/dex_ir_builder.cc b/dexlayout/dex_ir_builder.cc
index ca6ff9e514..947d3d5297 100644
--- a/dexlayout/dex_ir_builder.cc
+++ b/dexlayout/dex_ir_builder.cc
@@ -115,6 +115,8 @@ template<class T> class CollectionMap : public CollectionBase {
return it != collection_.end() ? it->second : nullptr;
}
+ uint32_t Size() const override { return size(); }
+
// Lower case for template interop with std::map.
uint32_t size() const { return collection_.size(); }
std::map<uint32_t, T*>& Collection() { return collection_; }
diff --git a/imgdiag/imgdiag.cc b/imgdiag/imgdiag.cc
index ebc18fc5ff..6ecf90151d 100644
--- a/imgdiag/imgdiag.cc
+++ b/imgdiag/imgdiag.cc
@@ -26,6 +26,7 @@
#include <unordered_set>
#include <vector>
+#include <android-base/parseint.h>
#include "android-base/stringprintf.h"
#include "art_field-inl.h"
@@ -1682,14 +1683,14 @@ struct ImgDiagArgs : public CmdlineArgs {
if (option.starts_with("--image-diff-pid=")) {
const char* image_diff_pid = option.substr(strlen("--image-diff-pid=")).data();
- if (!ParseInt(image_diff_pid, &image_diff_pid_)) {
+ if (!android::base::ParseInt(image_diff_pid, &image_diff_pid_)) {
*error_msg = "Image diff pid out of range";
return kParseError;
}
} else if (option.starts_with("--zygote-diff-pid=")) {
const char* zygote_diff_pid = option.substr(strlen("--zygote-diff-pid=")).data();
- if (!ParseInt(zygote_diff_pid, &zygote_diff_pid_)) {
+ if (!android::base::ParseInt(zygote_diff_pid, &zygote_diff_pid_)) {
*error_msg = "Zygote diff pid out of range";
return kParseError;
}
diff --git a/libartbase/base/utils.cc b/libartbase/base/utils.cc
index 761c6113d6..74cc5b97b2 100644
--- a/libartbase/base/utils.cc
+++ b/libartbase/base/utils.cc
@@ -38,6 +38,12 @@
#include "AvailabilityMacros.h" // For MAC_OS_X_VERSION_MAX_ALLOWED
#endif
+#if defined(__BIONIC__)
+// membarrier(2) is only supported for target builds (b/111199492).
+#include <linux/membarrier.h>
+#include <sys/syscall.h>
+#endif
+
#if defined(__linux__)
#include <linux/unistd.h>
#endif
@@ -207,4 +213,42 @@ void SleepForever() {
}
}
+bool FlushInstructionPipeline() {
+ // membarrier(2) is only supported for target builds (b/111199492).
+#if defined(__BIONIC__)
+ static constexpr int kSyncCoreMask =
+ MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE |
+ MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE;
+ static bool have_probed = false;
+ static bool have_sync_core = false;
+
+ if (UNLIKELY(!have_probed)) {
+ // Probe membarrier(2) commands supported by kernel.
+ int commands = syscall(__NR_membarrier, MEMBARRIER_CMD_QUERY, 0);
+ if (commands >= 0) {
+ have_sync_core = (commands & kSyncCoreMask) == kSyncCoreMask;
+ if (have_sync_core) {
+ // Register with kernel that we'll be using the private expedited sync core command.
+ CheckedCall(syscall,
+ "membarrier register sync core",
+ __NR_membarrier,
+ MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE,
+ 0);
+ }
+ }
+ have_probed = true;
+ }
+
+ if (have_sync_core) {
+ CheckedCall(syscall,
+ "membarrier sync core",
+ __NR_membarrier,
+ MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE,
+ 0);
+ return true;
+ }
+#endif // defined(__BIONIC__)
+ return false;
+}
+
} // namespace art
diff --git a/libartbase/base/utils.h b/libartbase/base/utils.h
index ba61e1b0a3..d85960d811 100644
--- a/libartbase/base/utils.h
+++ b/libartbase/base/utils.h
@@ -24,6 +24,7 @@
#include <string>
#include <android-base/logging.h>
+#include <android-base/parseint.h>
#include "casts.h"
#include "enums.h"
@@ -33,34 +34,6 @@
namespace art {
-template <typename T>
-bool ParseUint(const char *in, T* out) {
- char* end;
- unsigned long long int result = strtoull(in, &end, 0); // NOLINT(runtime/int)
- if (in == end || *end != '\0') {
- return false;
- }
- if (std::numeric_limits<T>::max() < result) {
- return false;
- }
- *out = static_cast<T>(result);
- return true;
-}
-
-template <typename T>
-bool ParseInt(const char* in, T* out) {
- char* end;
- long long int result = strtoll(in, &end, 0); // NOLINT(runtime/int)
- if (in == end || *end != '\0') {
- return false;
- }
- if (result < std::numeric_limits<T>::min() || std::numeric_limits<T>::max() < result) {
- return false;
- }
- *out = static_cast<T>(result);
- return true;
-}
-
static inline uint32_t PointerToLowMemUInt32(const void* p) {
uintptr_t intp = reinterpret_cast<uintptr_t>(p);
DCHECK_LE(intp, 0xFFFFFFFFU);
@@ -130,7 +103,7 @@ static void ParseIntOption(const StringPiece& option,
DCHECK(option.starts_with(option_prefix)) << option << " " << option_prefix;
const char* value_string = option.substr(option_prefix.size()).data();
int64_t parsed_integer_value = 0;
- if (!ParseInt(value_string, &parsed_integer_value)) {
+ if (!android::base::ParseInt(value_string, &parsed_integer_value)) {
usage("Failed to parse %s '%s' as an integer", option_name.c_str(), value_string);
}
*out = dchecked_integral_cast<T>(parsed_integer_value);
@@ -179,16 +152,19 @@ static T GetRandomNumber(T min, T max) {
// Sleep forever and never come back.
NO_RETURN void SleepForever();
-inline void FlushInstructionCache(char* begin, char* end) {
- __builtin___clear_cache(begin, end);
+inline void FlushDataCache(void* begin, void* end) {
+ __builtin___clear_cache(reinterpret_cast<char*>(begin), reinterpret_cast<char*>(end));
}
-inline void FlushDataCache(char* begin, char* end) {
+inline void FlushInstructionCache(void* begin, void* end) {
// Same as FlushInstructionCache for lack of other builtin. __builtin___clear_cache
// flushes both caches.
- __builtin___clear_cache(begin, end);
+ __builtin___clear_cache(reinterpret_cast<char*>(begin), reinterpret_cast<char*>(end));
}
+// Flush instruction pipeline. Returns true on success, false if feature is unsupported.
+bool FlushInstructionPipeline();
+
template <typename T>
constexpr PointerSize ConvertToPointerSize(T any) {
if (any == 4 || any == 8) {
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index fc7f5b7666..ac9ece785a 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -28,6 +28,7 @@
#include <vector>
#include "android-base/logging.h"
+#include "android-base/parseint.h"
#include "android-base/stringprintf.h"
#include "android-base/strings.h"
@@ -3380,7 +3381,7 @@ struct OatdumpArgs : public CmdlineArgs {
} else if (option.starts_with("--export-dex-to=")) {
export_dex_location_ = option.substr(strlen("--export-dex-to=")).data();
} else if (option.starts_with("--addr2instr=")) {
- if (!ParseUint(option.substr(strlen("--addr2instr=")).data(), &addr2instr_)) {
+ if (!android::base::ParseUint(option.substr(strlen("--addr2instr=")).data(), &addr2instr_)) {
*error_msg = "Address conversion failed";
return kParseError;
}
diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc
index aaa3e8339f..5d38e8bfed 100644
--- a/patchoat/patchoat.cc
+++ b/patchoat/patchoat.cc
@@ -26,6 +26,7 @@
#include <vector>
#include "android-base/file.h"
+#include <android-base/parseint.h>
#include "android-base/stringprintf.h"
#include "android-base/strings.h"
@@ -630,7 +631,7 @@ bool PatchOat::Patch(const std::string& image_location,
std::string image_relocation_filename =
output_image_relocation_directory
+ (android::base::StartsWith(original_image_filename, "/") ? "" : "/")
- + original_image_filename.substr(original_image_filename.find_last_of("/"));
+ + original_image_filename.substr(original_image_filename.find_last_of('/'));
int64_t input_image_size = input_image->GetLength();
if (input_image_size < 0) {
LOG(ERROR) << "Error while getting input image size";
@@ -1272,7 +1273,7 @@ static int patchoat(int argc, char **argv) {
} else if (option.starts_with("--base-offset-delta=")) {
const char* base_delta_str = option.substr(strlen("--base-offset-delta=")).data();
base_delta_set = true;
- if (!ParseInt(base_delta_str, &base_delta)) {
+ if (!android::base::ParseInt(base_delta_str, &base_delta)) {
Usage("Failed to parse --base-offset-delta argument '%s' as an off_t", base_delta_str);
}
} else if (option == "--dump-timings") {
diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h
index f693524a6c..9b69166567 100644
--- a/runtime/art_method-inl.h
+++ b/runtime/art_method-inl.h
@@ -417,7 +417,6 @@ inline HiddenApiAccessFlags::ApiList ArtMethod::GetHiddenApiAccessFlags()
case Intrinsics::kMemoryPokeIntNative:
case Intrinsics::kMemoryPokeLongNative:
case Intrinsics::kMemoryPokeShortNative:
- return HiddenApiAccessFlags::kDarkGreylist;
case Intrinsics::kVarHandleFullFence:
case Intrinsics::kVarHandleAcquireFence:
case Intrinsics::kVarHandleReleaseFence:
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index e19dedcebd..511d468412 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -483,9 +483,17 @@ bool ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b
mirror::ObjectArray<mirror::Object>::ClassSize(image_pointer_size_))));
object_array_class->SetComponentType(java_lang_Object.Get());
- // Setup String.
+ // Setup java.lang.String.
+ //
+ // We make this class non-movable for the unlikely case where it were to be
+ // moved by a sticky-bit (minor) collection when using the Generational
+ // Concurrent Copying (CC) collector, potentially creating a stale reference
+ // in the `klass_` field of one of its instances allocated in the Large-Object
+ // Space (LOS) -- see the comment about the dirty card scanning logic in
+ // art::gc::collector::ConcurrentCopying::MarkingPhase.
Handle<mirror::Class> java_lang_String(hs.NewHandle(
- AllocClass(self, java_lang_Class.Get(), mirror::String::ClassSize(image_pointer_size_))));
+ AllocClass</* kMovable */ false>(
+ self, java_lang_Class.Get(), mirror::String::ClassSize(image_pointer_size_))));
java_lang_String->SetStringClass();
mirror::Class::SetStatus(java_lang_String, ClassStatus::kResolved, self);
@@ -528,13 +536,13 @@ bool ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b
// Create int array type for native pointer arrays (for example vtables) on 32-bit archs.
Handle<mirror::Class> int_array_class(hs.NewHandle(
- AllocClass(self, java_lang_Class.Get(), mirror::Array::ClassSize(image_pointer_size_))));
+ AllocPrimitiveArrayClass(self, java_lang_Class.Get())));
int_array_class->SetComponentType(GetClassRoot(ClassRoot::kPrimitiveInt, this));
SetClassRoot(ClassRoot::kIntArrayClass, int_array_class.Get());
// Create long array type for native pointer arrays (for example vtables) on 64-bit archs.
Handle<mirror::Class> long_array_class(hs.NewHandle(
- AllocClass(self, java_lang_Class.Get(), mirror::Array::ClassSize(image_pointer_size_))));
+ AllocPrimitiveArrayClass(self, java_lang_Class.Get())));
long_array_class->SetComponentType(GetClassRoot(ClassRoot::kPrimitiveLong, this));
SetClassRoot(ClassRoot::kLongArrayClass, long_array_class.Get());
@@ -610,20 +618,29 @@ bool ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b
CHECK_EQ(dalvik_system_ClassExt->GetObjectSize(), mirror::ClassExt::InstanceSize());
// Setup the primitive array type classes - can't be done until Object has a vtable.
- SetClassRoot(ClassRoot::kBooleanArrayClass, FindSystemClass(self, "[Z"));
+ AllocAndSetPrimitiveArrayClassRoot(self,
+ java_lang_Class.Get(),
+ ClassRoot::kBooleanArrayClass,
+ ClassRoot::kPrimitiveBoolean,
+ "[Z");
- SetClassRoot(ClassRoot::kByteArrayClass, FindSystemClass(self, "[B"));
+ AllocAndSetPrimitiveArrayClassRoot(
+ self, java_lang_Class.Get(), ClassRoot::kByteArrayClass, ClassRoot::kPrimitiveByte, "[B");
- SetClassRoot(ClassRoot::kCharArrayClass, FindSystemClass(self, "[C"));
+ AllocAndSetPrimitiveArrayClassRoot(
+ self, java_lang_Class.Get(), ClassRoot::kCharArrayClass, ClassRoot::kPrimitiveChar, "[C");
- SetClassRoot(ClassRoot::kShortArrayClass, FindSystemClass(self, "[S"));
+ AllocAndSetPrimitiveArrayClassRoot(
+ self, java_lang_Class.Get(), ClassRoot::kShortArrayClass, ClassRoot::kPrimitiveShort, "[S");
CheckSystemClass(self, int_array_class, "[I");
CheckSystemClass(self, long_array_class, "[J");
- SetClassRoot(ClassRoot::kFloatArrayClass, FindSystemClass(self, "[F"));
+ AllocAndSetPrimitiveArrayClassRoot(
+ self, java_lang_Class.Get(), ClassRoot::kFloatArrayClass, ClassRoot::kPrimitiveFloat, "[F");
- SetClassRoot(ClassRoot::kDoubleArrayClass, FindSystemClass(self, "[D"));
+ AllocAndSetPrimitiveArrayClassRoot(
+ self, java_lang_Class.Get(), ClassRoot::kDoubleArrayClass, ClassRoot::kPrimitiveDouble, "[D");
// Run Class through FindSystemClass. This initializes the dex_cache_ fields and register it
// in class_table_.
@@ -2165,13 +2182,14 @@ ObjPtr<mirror::DexCache> ClassLinker::AllocAndInitializeDexCache(Thread* self,
return dex_cache;
}
+template <bool kMovable>
ObjPtr<mirror::Class> ClassLinker::AllocClass(Thread* self,
ObjPtr<mirror::Class> java_lang_Class,
uint32_t class_size) {
DCHECK_GE(class_size, sizeof(mirror::Class));
gc::Heap* heap = Runtime::Current()->GetHeap();
mirror::Class::InitializeClassVisitor visitor(class_size);
- ObjPtr<mirror::Object> k = kMovingClasses ?
+ ObjPtr<mirror::Object> k = (kMovingClasses && kMovable) ?
heap->AllocObject<true>(self, java_lang_Class, class_size, visitor) :
heap->AllocNonMovableObject<true>(self, java_lang_Class, class_size, visitor);
if (UNLIKELY(k == nullptr)) {
@@ -2185,6 +2203,18 @@ ObjPtr<mirror::Class> ClassLinker::AllocClass(Thread* self, uint32_t class_size)
return AllocClass(self, GetClassRoot<mirror::Class>(this), class_size);
}
+ObjPtr<mirror::Class> ClassLinker::AllocPrimitiveArrayClass(Thread* self,
+ ObjPtr<mirror::Class> java_lang_Class) {
+ // We make this class non-movable for the unlikely case where it were to be
+ // moved by a sticky-bit (minor) collection when using the Generational
+ // Concurrent Copying (CC) collector, potentially creating a stale reference
+ // in the `klass_` field of one of its instances allocated in the Large-Object
+ // Space (LOS) -- see the comment about the dirty card scanning logic in
+ // art::gc::collector::ConcurrentCopying::MarkingPhase.
+ return AllocClass</* kMovable */ false>(
+ self, java_lang_Class, mirror::Array::ClassSize(image_pointer_size_));
+}
+
ObjPtr<mirror::ObjectArray<mirror::StackTraceElement>> ClassLinker::AllocStackTraceElementArray(
Thread* self,
size_t length) {
@@ -3648,10 +3678,22 @@ ObjPtr<mirror::Class> ClassLinker::CreateArrayClass(Thread* self,
new_class.Assign(GetClassRoot<mirror::ObjectArray<mirror::Object>>(this));
} else if (strcmp(descriptor, "[Ljava/lang/String;") == 0) {
new_class.Assign(GetClassRoot<mirror::ObjectArray<mirror::String>>(this));
+ } else if (strcmp(descriptor, "[Z") == 0) {
+ new_class.Assign(GetClassRoot<mirror::BooleanArray>(this));
+ } else if (strcmp(descriptor, "[B") == 0) {
+ new_class.Assign(GetClassRoot<mirror::ByteArray>(this));
+ } else if (strcmp(descriptor, "[C") == 0) {
+ new_class.Assign(GetClassRoot<mirror::CharArray>(this));
+ } else if (strcmp(descriptor, "[S") == 0) {
+ new_class.Assign(GetClassRoot<mirror::ShortArray>(this));
} else if (strcmp(descriptor, "[I") == 0) {
new_class.Assign(GetClassRoot<mirror::IntArray>(this));
} else if (strcmp(descriptor, "[J") == 0) {
new_class.Assign(GetClassRoot<mirror::LongArray>(this));
+ } else if (strcmp(descriptor, "[F") == 0) {
+ new_class.Assign(GetClassRoot<mirror::FloatArray>(this));
+ } else if (strcmp(descriptor, "[D") == 0) {
+ new_class.Assign(GetClassRoot<mirror::DoubleArray>(this));
}
}
if (new_class == nullptr) {
@@ -8607,6 +8649,19 @@ void ClassLinker::SetClassRoot(ClassRoot class_root, ObjPtr<mirror::Class> klass
class_roots->Set<false>(index, klass);
}
+void ClassLinker::AllocAndSetPrimitiveArrayClassRoot(Thread* self,
+ ObjPtr<mirror::Class> java_lang_Class,
+ ClassRoot primitive_array_class_root,
+ ClassRoot primitive_class_root,
+ const char* descriptor) {
+ StackHandleScope<1> hs(self);
+ Handle<mirror::Class> primitive_array_class(hs.NewHandle(
+ AllocPrimitiveArrayClass(self, java_lang_Class)));
+ primitive_array_class->SetComponentType(GetClassRoot(primitive_class_root, this));
+ SetClassRoot(primitive_array_class_root, primitive_array_class.Get());
+ CheckSystemClass(self, primitive_array_class, descriptor);
+}
+
jobject ClassLinker::CreateWellKnownClassLoader(Thread* self,
const std::vector<const DexFile*>& dex_files,
jclass loader_class,
@@ -8941,7 +8996,7 @@ ObjPtr<mirror::IfTable> ClassLinker::AllocIfTable(Thread* self, size_t ifcount)
ifcount * mirror::IfTable::kMax)));
}
-// Instantiate ResolveMethod.
+// Instantiate ClassLinker::ResolveMethod.
template ArtMethod* ClassLinker::ResolveMethod<ClassLinker::ResolveMode::kCheckICCEAndIAE>(
uint32_t method_idx,
Handle<mirror::DexCache> dex_cache,
@@ -8955,4 +9010,14 @@ template ArtMethod* ClassLinker::ResolveMethod<ClassLinker::ResolveMode::kNoChec
ArtMethod* referrer,
InvokeType type);
+// Instantiate ClassLinker::AllocClass.
+template ObjPtr<mirror::Class> ClassLinker::AllocClass</* kMovable */ true>(
+ Thread* self,
+ ObjPtr<mirror::Class> java_lang_Class,
+ uint32_t class_size);
+template ObjPtr<mirror::Class> ClassLinker::AllocClass</* kMovable */ false>(
+ Thread* self,
+ ObjPtr<mirror::Class> java_lang_Class,
+ uint32_t class_size);
+
} // namespace art
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index e4d9c96696..efe29d3127 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -775,7 +775,11 @@ class ClassLinker {
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_);
- // For early bootstrapping by Init
+ // For early bootstrapping by Init.
+ // If we do not allow moving classes (`art::kMovingClass` is false) or if
+ // parameter `kMovable` is false (or both), the class object is allocated in
+ // the non-moving space.
+ template <bool kMovable = true>
ObjPtr<mirror::Class> AllocClass(Thread* self,
ObjPtr<mirror::Class> java_lang_Class,
uint32_t class_size)
@@ -789,6 +793,12 @@ class ClassLinker {
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!Roles::uninterruptible_);
+ // Allocate a primitive array class.
+ ObjPtr<mirror::Class> AllocPrimitiveArrayClass(Thread* self,
+ ObjPtr<mirror::Class> java_lang_Class)
+ REQUIRES_SHARED(Locks::mutator_lock_)
+ REQUIRES(!Roles::uninterruptible_);
+
ObjPtr<mirror::DexCache> AllocDexCache(/*out*/ ObjPtr<mirror::String>* out_location,
Thread* self,
const DexFile& dex_file)
@@ -1206,6 +1216,20 @@ class ClassLinker {
void SetClassRoot(ClassRoot class_root, ObjPtr<mirror::Class> klass)
REQUIRES_SHARED(Locks::mutator_lock_);
+ // Allocate primitive array class for primitive with class root
+ // `primitive_class_root`, and associate it to class root
+ // `primitive_array_class_root`.
+ //
+ // Also check this class returned when searching system classes for
+ // `descriptor` matches the allocated class.
+ void AllocAndSetPrimitiveArrayClassRoot(Thread* self,
+ ObjPtr<mirror::Class> java_lang_Class,
+ ClassRoot primitive_array_class_root,
+ ClassRoot primitive_class_root,
+ const char* descriptor)
+ REQUIRES_SHARED(Locks::mutator_lock_)
+ REQUIRES(!Roles::uninterruptible_);
+
// Return the quick generic JNI stub for testing.
const void* GetRuntimeQuickGenericJniStub() const;
diff --git a/runtime/class_loader_context.cc b/runtime/class_loader_context.cc
index 2bd541118b..f6b764ddc0 100644
--- a/runtime/class_loader_context.cc
+++ b/runtime/class_loader_context.cc
@@ -16,6 +16,8 @@
#include "class_loader_context.h"
+#include <android-base/parseint.h>
+
#include "art_field-inl.h"
#include "base/dchecked_vector.h"
#include "base/stl_util.h"
@@ -120,7 +122,7 @@ bool ClassLoaderContext::ParseClassLoaderSpec(const std::string& class_loader_sp
return false;
}
uint32_t checksum = 0;
- if (!ParseInt(dex_file_with_checksum[1].c_str(), &checksum)) {
+ if (!android::base::ParseInt(dex_file_with_checksum[1].c_str(), &checksum)) {
return false;
}
class_loader_chain_.back().classpath.push_back(dex_file_with_checksum[0]);
diff --git a/runtime/gc/collector/concurrent_copying.cc b/runtime/gc/collector/concurrent_copying.cc
index 0c187675ba..eede5a56c0 100644
--- a/runtime/gc/collector/concurrent_copying.cc
+++ b/runtime/gc/collector/concurrent_copying.cc
@@ -905,13 +905,8 @@ void ConcurrentCopying::MarkingPhase() {
// during a minor (young-generation) collection:
// - In the case where we run with a boot image, these classes are part of the image space,
// which is an immune space.
- // - In the case where we run without a boot image, these classes are allocated in the region
- // space (main space), but they are not expected to move during a minor collection (this
- // would only happen if those classes were allocated between a major and a minor
- // collections, which is unlikely -- we don't expect any GC to happen before these
- // fundamental classes are initialized). Note that these classes could move during a major
- // collection though, but this is fine: in that case, the whole heap is traced and the card
- // table logic below is not used.
+ // - In the case where we run without a boot image, these classes are allocated in the
+ // non-moving space (see art::ClassLinker::InitWithoutImage).
Runtime::Current()->GetHeap()->GetCardTable()->Scan<false>(
space->GetMarkBitmap(),
space->Begin(),
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 589e9a4826..e76d35d0f9 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -450,6 +450,7 @@ Heap::Heap(size_t initial_size,
// Non moving space is always dlmalloc since we currently don't have support for multiple
// active rosalloc spaces.
const size_t size = non_moving_space_mem_map.Size();
+ const void* non_moving_space_mem_map_begin = non_moving_space_mem_map.Begin();
non_moving_space_ = space::DlMallocSpace::CreateFromMemMap(std::move(non_moving_space_mem_map),
"zygote / non moving space",
kDefaultStartingSize,
@@ -457,9 +458,9 @@ Heap::Heap(size_t initial_size,
size,
size,
/* can_move_objects */ false);
- non_moving_space_->SetFootprintLimit(non_moving_space_->Capacity());
CHECK(non_moving_space_ != nullptr) << "Failed creating non moving space "
- << non_moving_space_mem_map.Begin();
+ << non_moving_space_mem_map_begin;
+ non_moving_space_->SetFootprintLimit(non_moving_space_->Capacity());
AddSpace(non_moving_space_);
}
// Create other spaces based on whether or not we have a moving GC.
diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc
index 2b2898c195..184aba815d 100644
--- a/runtime/jit/jit_code_cache.cc
+++ b/runtime/jit/jit_code_cache.cc
@@ -28,6 +28,7 @@
#include "base/stl_util.h"
#include "base/systrace.h"
#include "base/time_utils.h"
+#include "base/utils.h"
#include "cha.h"
#include "debugger_interface.h"
#include "dex/dex_file_loader.h"
@@ -53,8 +54,9 @@
namespace art {
namespace jit {
-static constexpr int kProtData = PROT_READ | PROT_WRITE;
static constexpr int kProtCode = PROT_READ | PROT_EXEC;
+static constexpr int kProtData = PROT_READ | PROT_WRITE;
+static constexpr int kProtProfile = PROT_READ;
static constexpr size_t kCodeSizeLogThreshold = 50 * KB;
static constexpr size_t kStackMapSizeLogThreshold = 50 * KB;
@@ -192,7 +194,7 @@ JitCodeCache* JitCodeCache::Create(size_t initial_capacity,
// to profile system server.
// NOTE 2: We could just not create the code section at all but we will need to
// special case too many cases.
- int memmap_flags_prot_code = used_only_for_profile_data ? (kProtCode & ~PROT_EXEC) : kProtCode;
+ int memmap_flags_prot_code = used_only_for_profile_data ? kProtProfile : kProtCode;
std::string error_str;
// Map name specific for android_os_Debug.cpp accounting.
@@ -799,8 +801,18 @@ uint8_t* JitCodeCache::CommitCodeInternal(Thread* self,
//
// For reference, this behavior is caused by this commit:
// https://android.googlesource.com/kernel/msm/+/3fbe6bc28a6b9939d0650f2f17eb5216c719950c
- FlushInstructionCache(reinterpret_cast<char*>(code_ptr),
- reinterpret_cast<char*>(code_ptr + code_size));
+ FlushInstructionCache(code_ptr, code_ptr + code_size);
+
+ // Ensure CPU instruction pipelines are flushed for all cores. This is necessary for
+ // correctness as code may still be in instruction pipelines despite the i-cache flush. It is
+ // not safe to assume that changing permissions with mprotect (RX->RWX->RX) will cause a TLB
+ // shootdown (incidentally invalidating the CPU pipelines by sending an IPI to all cores to
+ // notify them of the TLB invalidation). Some architectures, notably ARM and ARM64, have
+ // hardware support that broadcasts TLB invalidations and so their kernels have no software
+ // based TLB shootdown. FlushInstructionPipeline() is a wrapper around the Linux
+ // membarrier(MEMBARRIER_CMD_PRIVATE_EXPEDITED) syscall which does the appropriate flushing.
+ FlushInstructionPipeline();
+
DCHECK(!Runtime::Current()->IsAotCompiler());
if (has_should_deoptimize_flag) {
method_header->SetHasShouldDeoptimizeFlag();
@@ -858,8 +870,7 @@ uint8_t* JitCodeCache::CommitCodeInternal(Thread* self,
FillRootTable(roots_data, roots);
{
// Flush data cache, as compiled code references literals in it.
- FlushDataCache(reinterpret_cast<char*>(roots_data),
- reinterpret_cast<char*>(roots_data + data_size));
+ FlushDataCache(roots_data, roots_data + data_size);
}
method_code_map_.Put(code_ptr, method);
if (osr) {
diff --git a/test/004-StackWalk/build b/test/004-StackWalk/build
index eeecbfcc40..3de541c75d 100644
--- a/test/004-StackWalk/build
+++ b/test/004-StackWalk/build
@@ -18,10 +18,8 @@
set -e
# This test depends on the exact format of the DEX file. Since dx is deprecated,
-# the classes.dex file is packaged as a test input. It was created with:
-#
-# $ javac -g -Xlint:-options -source 1.7 -target 1.7 -d classes src/Main.java
-# $ dx --debug --dex --output=classes.dex classes
+# the classes.dex file is packaged as a test input. See src/Main.java file
+# to check how it was created.
# Wrapper function for javac which for this test does nothing as the
# test uses a pre-built DEX file.
diff --git a/test/004-StackWalk/classes.dex b/test/004-StackWalk/classes.dex
index ad452960c3..61a7277cf9 100644
--- a/test/004-StackWalk/classes.dex
+++ b/test/004-StackWalk/classes.dex
Binary files differ
diff --git a/test/004-StackWalk/src/Main.java b/test/004-StackWalk/src/Main.java
index 072b1d0c4d..2a098f7686 100644
--- a/test/004-StackWalk/src/Main.java
+++ b/test/004-StackWalk/src/Main.java
@@ -1,19 +1,36 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+// This test depends on the exact format of the DEX file. Since dx is deprecated,
+// the classes.dex file is packaged as a test input. It was created with:
+//
+// $ javac -g -Xlint:-options -source 1.7 -target 1.7 -d classes src/Main.java
+// $ dx --debug --dex --output=classes.dex classes
+
public class Main {
public Main() {
}
- boolean doThrow = false;
-
int $noinline$f() throws Exception {
- g(1);
- g(2);
-
- // This currently defeats inlining of `f`.
- if (doThrow) { throw new Error(); }
+ $noinline$g(1);
+ $noinline$g(2);
return 0;
}
- void g(int num_calls) {
+ void $noinline$g(int num_calls) {
if (num_calls == 1) {
System.out.println("1st call");
} else if (num_calls == 2) {
@@ -81,11 +98,14 @@ public class Main {
s4 = s18 = s19;
s += s4;
s += s18;
- stackmap(0);
- return s;
+ // Add a branch to workaround ART's large methods without branches heuristic.
+ if (testStackWalk(0) != 0) {
+ return s;
+ }
+ return s18;
}
- native int stackmap(int x);
+ native int testStackWalk(int x);
public static void main(String[] args) throws Exception {
System.loadLibrary(args[0]);
diff --git a/test/004-StackWalk/stack_walk_jni.cc b/test/004-StackWalk/stack_walk_jni.cc
index 89e2e660d9..53e0dae13d 100644
--- a/test/004-StackWalk/stack_walk_jni.cc
+++ b/test/004-StackWalk/stack_walk_jni.cc
@@ -20,7 +20,7 @@
namespace art {
-#define CHECK_REGS(...) do { \
+#define CHECK_REGS_ARE_REFERENCES(...) do { \
int t[] = {__VA_ARGS__}; \
int t_size = sizeof(t) / sizeof(*t); \
CheckReferences(t, t_size, GetNativePcOffset()); \
@@ -43,58 +43,60 @@ class TestReferenceMapVisitor : public CheckReferenceMapVisitor {
// Given the method name and the number of times the method has been called,
// we know the Dex registers with live reference values. Assert that what we
// find is what is expected.
- if (m_name == "f") {
+ if (m_name == "$noinline$f") {
if (gJava_StackWalk_refmap_calls == 1) {
CHECK_EQ(1U, GetDexPc());
- CHECK_REGS(4);
+ CHECK_REGS_ARE_REFERENCES(1);
} else {
CHECK_EQ(gJava_StackWalk_refmap_calls, 2);
CHECK_EQ(5U, GetDexPc());
- CHECK_REGS(4);
+ CHECK_REGS_ARE_REFERENCES(1);
}
- } else if (m_name == "g") {
+ found_f_ = true;
+ } else if (m_name == "$noinline$g") {
if (gJava_StackWalk_refmap_calls == 1) {
CHECK_EQ(0xcU, GetDexPc());
- CHECK_REGS(0, 2); // Note that v1 is not in the minimal root set
+ CHECK_REGS_ARE_REFERENCES(0, 2); // Note that v1 is not in the minimal root set
} else {
CHECK_EQ(gJava_StackWalk_refmap_calls, 2);
CHECK_EQ(0xcU, GetDexPc());
- CHECK_REGS(0, 2);
+ CHECK_REGS_ARE_REFERENCES(0, 2);
}
+ found_g_ = true;
} else if (m_name == "shlemiel") {
if (gJava_StackWalk_refmap_calls == 1) {
CHECK_EQ(0x380U, GetDexPc());
- CHECK_REGS(2, 4, 5, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 21, 25);
+ CHECK_REGS_ARE_REFERENCES(2, 4, 5, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 21, 25);
} else {
CHECK_EQ(gJava_StackWalk_refmap_calls, 2);
CHECK_EQ(0x380U, GetDexPc());
- CHECK_REGS(2, 4, 5, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 21, 25);
+ CHECK_REGS_ARE_REFERENCES(2, 4, 5, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 21, 25);
}
+ found_shlemiel_ = true;
}
return true;
}
-};
-extern "C" JNIEXPORT jint JNICALL Java_Main_stackmap(JNIEnv*, jobject, jint count) {
- ScopedObjectAccess soa(Thread::Current());
- CHECK_EQ(count, 0);
- gJava_StackWalk_refmap_calls++;
-
- // Visitor
- TestReferenceMapVisitor mapper(soa.Self());
- mapper.WalkStack();
+ ~TestReferenceMapVisitor() {
+ }
- return count + 1;
-}
+ bool found_f_ = false;
+ bool found_g_ = false;
+ bool found_shlemiel_ = false;
+};
-extern "C" JNIEXPORT jint JNICALL Java_Main_refmap2(JNIEnv*, jobject, jint count) {
+extern "C" JNIEXPORT jint JNICALL Java_Main_testStackWalk(JNIEnv*, jobject, jint count) {
ScopedObjectAccess soa(Thread::Current());
+ CHECK_EQ(count, 0);
gJava_StackWalk_refmap_calls++;
// Visitor
TestReferenceMapVisitor mapper(soa.Self());
mapper.WalkStack();
+ CHECK(mapper.found_f_);
+ CHECK(mapper.found_g_);
+ CHECK(mapper.found_shlemiel_);
return count + 1;
}
diff --git a/test/669-moveable-string-class-equals/expected.txt b/test/669-moveable-string-class-equals/expected.txt
deleted file mode 100644
index 6a5618ebc6..0000000000
--- a/test/669-moveable-string-class-equals/expected.txt
+++ /dev/null
@@ -1 +0,0 @@
-JNI_OnLoad called
diff --git a/test/669-moveable-string-class-equals/info.txt b/test/669-moveable-string-class-equals/info.txt
deleted file mode 100644
index 1d3202ef46..0000000000
--- a/test/669-moveable-string-class-equals/info.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-Regression test for String.equals() intrinsic instanceof check
-when the String.class is moveable.
diff --git a/test/669-moveable-string-class-equals/run b/test/669-moveable-string-class-equals/run
deleted file mode 100755
index 7c74d8ca0e..0000000000
--- a/test/669-moveable-string-class-equals/run
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/bin/bash
-#
-# Copyright (C) 2017 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.
-
-# Run without image, so that String.class is moveable.
-# Reduce heap size to force more frequent GCs.
-${RUN} --no-image --runtime-option -Xmx16m "$@"
diff --git a/test/669-moveable-string-class-equals/src/Main.java b/test/669-moveable-string-class-equals/src/Main.java
deleted file mode 100644
index d182d51a25..0000000000
--- a/test/669-moveable-string-class-equals/src/Main.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-public class Main {
- public static void main(String[] args) {
- System.loadLibrary(args[0]);
- if (!hasJit()) {
- // Make the test pass if not using JIT.
- return;
- }
- if (hasImage()) {
- throw new Error("The `run` script should prevent this test from running with an image!");
- }
- if (!isClassMoveable(String.class)) {
- throw new Error("String.class not moveable despite running without image!");
- }
-
- // Make sure the Main.test() is JIT-compiled and then call it.
- ensureJitCompiled(Main.class, "test");
- test();
- }
-
- public static void test() {
- int length = 5;
-
- // Hide the type of these strings in an Object array,
- // so that we treat them as Object for the String.equals() below.
- Object[] array = new Object[length];
- for (int i = 0; i != length; ++i) {
- array[i] = "V" + i;
- }
-
- // Continually check string equality between a newly allocated String and an
- // already allocated String with the same contents while allocating over 128MiB
- // memory (with heap size limited to 16MiB), ensuring we run GC and stress the
- // instanceof check in the String.equals() implementation.
- for (int count = 0; count != 128 * 1024; ++count) {
- for (int i = 0; i != length; ++i) {
- allocateAtLeast1KiB();
- assertTrue(("V" + i).equals(array[i]));
- }
- }
- }
-
- public static void allocateAtLeast1KiB() {
- // Give GC more work by allocating Object arrays.
- memory[allocationIndex] = new Object[1024 / 4];
- ++allocationIndex;
- if (allocationIndex == memory.length) {
- allocationIndex = 0;
- }
- }
-
- public static void assertTrue(boolean value) {
- if (!value) {
- throw new Error("Assertion failed!");
- }
- }
-
- private native static boolean hasJit();
- private native static boolean hasImage();
- private native static boolean isClassMoveable(Class<?> cls);
- private static native void ensureJitCompiled(Class<?> itf, String method_name);
-
- // We shall retain some allocated memory and release old allocations
- // so that the GC has something to do.
- public static Object[] memory = new Object[4096];
- public static int allocationIndex = 0;
-}
diff --git a/test/StackWalk2/StackWalk2.java b/test/StackWalk2/StackWalk2.java
deleted file mode 100644
index 5e7b22c252..0000000000
--- a/test/StackWalk2/StackWalk2.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-public class StackWalk2 {
- // use v1 for this
-
- String str = new String(); // use v0 for str in <init>
-
- int f() {
- g(1); // use v0 for 1, v1 for this
- g(2); // use v0 for 2, v1 for this
- strTest(); // use v1 for this
- return 0;
- }
-
- void g(int num_calls) throws RuntimeException {
- if (num_calls == 1) { // use v0 for 1, v3 for num_calls
- System.logI("1st call"); // use v0 for PrintStream, v1 for "1st call"
- refmap2(24); // use v0 for 24, v2 for this
- } else if (num_calls == 2) { // use v0 for 2, v3 for num_calls
- System.logI("2nd call"); // use v0 for PrintStream, v1 for "2nd call"
- refmap2(25); // use v0 for 24, v2 for this
- }
- throw new RuntimeException(); // use v0 for new RuntimeException
- }
-
- void strTest() {
- System.logI(str); // use v1 for PrintStream, v2, v3 for str
- str = null; // use v1 for null, v3 for str
- str = new String("ya"); // use v2 for "ya", v1 for new String
- String s = str; // use v0, v1, v3
- System.logI(str); // use v1 for PrintStream, v2, v3 for str
- System.logI(s); // use v1 for PrintStream, v0 for s
- s = null; // use v0
- System.logI(s); // use v1 for PrintStream, v0 for s
- }
-
- native int refmap2(int x);
-
- public static void main(String[] args) {
- System.loadLibrary(args[0]);
- StackWalk2 st = new StackWalk2();
- st.f();
- }
-}
diff --git a/test/common/runtime_state.cc b/test/common/runtime_state.cc
index da79164f12..c9b789e169 100644
--- a/test/common/runtime_state.cc
+++ b/test/common/runtime_state.cc
@@ -292,15 +292,6 @@ extern "C" JNIEXPORT void JNICALL Java_Main_fetchProfiles(JNIEnv*, jclass) {
code_cache->GetProfiledMethods(unused_locations, unused_vector);
}
-extern "C" JNIEXPORT jboolean JNICALL Java_Main_isClassMoveable(JNIEnv*,
- jclass,
- jclass cls) {
- Runtime* runtime = Runtime::Current();
- ScopedObjectAccess soa(Thread::Current());
- ObjPtr<mirror::Class> klass = soa.Decode<mirror::Class>(cls);
- return runtime->GetHeap()->IsMovableObject(klass);
-}
-
extern "C" JNIEXPORT void JNICALL Java_Main_waitForCompilation(JNIEnv*, jclass) {
jit::Jit* jit = Runtime::Current()->GetJit();
if (jit != nullptr) {
diff --git a/test/knownfailures.json b/test/knownfailures.json
index 6004f25285..05c9aa9157 100644
--- a/test/knownfailures.json
+++ b/test/knownfailures.json
@@ -697,9 +697,9 @@
"description": ["Tests that depend on input-vdex are not supported with compact dex"]
},
{
- "tests": "661-oat-writer-layout",
+ "tests": ["661-oat-writer-layout", "004-StackWalk"],
"variant": "interp-ac | interpreter | jit | no-prebuild | no-image | trace | redefine-stress | jvmti-stress",
- "description": ["Test is designed to only check --compiler-filter=speed"]
+ "description": ["Tests are designed to only check --optimizing"]
},
{
"tests": "674-HelloWorld-Dm",
diff --git a/tools/field-null-percent/fieldnull.cc b/tools/field-null-percent/fieldnull.cc
index 86459d238b..1bd122a1b2 100644
--- a/tools/field-null-percent/fieldnull.cc
+++ b/tools/field-null-percent/fieldnull.cc
@@ -147,7 +147,7 @@ static void VMDeathCb(jvmtiEnv* jvmti, JNIEnv* env ATTRIBUTE_UNUSED) {
delete list;
}
-static void CreateFieldList(jvmtiEnv* jvmti, JNIEnv* env, std::string args) {
+static void CreateFieldList(jvmtiEnv* jvmti, JNIEnv* env, const std::string& args) {
RequestList* list = nullptr;
CHECK_JVMTI(jvmti->Allocate(sizeof(*list), reinterpret_cast<unsigned char**>(&list)));
new (list) RequestList { .fields_ = GetRequestedFields(env, args), };
diff --git a/tools/libcore_gcstress_failures.txt b/tools/libcore_gcstress_failures.txt
index 965e85c359..fff1c70ad8 100644
--- a/tools/libcore_gcstress_failures.txt
+++ b/tools/libcore_gcstress_failures.txt
@@ -29,6 +29,7 @@
modes: [device],
names: ["libcore.java.lang.StringTest#testFastPathString_wellFormedUtf8Sequence",
"org.apache.harmony.tests.java.lang.ref.ReferenceQueueTest#test_remove",
+ "org.apache.harmony.tests.java.text.DateFormatTest#test_getAvailableLocales",
"org.apache.harmony.tests.java.util.TimerTest#testOverdueTaskExecutesImmediately",
"org.apache.harmony.tests.java.util.WeakHashMapTest#test_keySet_hasNext",
"libcore.java.text.DecimalFormatTest#testCurrencySymbolSpacing",