Merge "Add mterp checks after monitor entry/exit opcodes."
diff --git a/build/apex/Android.bp b/build/apex/Android.bp
index bca2959..8bddb5d 100644
--- a/build/apex/Android.bp
+++ b/build/apex/Android.bp
@@ -76,7 +76,6 @@
name: "com.android.runtime",
compile_multilib: "both",
manifest: "manifest.json",
- file_contexts: "file_contexts",
native_shared_libs: art_runtime_base_native_shared_libs
+ art_runtime_fake_native_shared_libs
+ art_runtime_debug_native_shared_libs,
diff --git a/build/apex/file_contexts b/build/apex/file_contexts
deleted file mode 100644
index 4d0df80..0000000
--- a/build/apex/file_contexts
+++ /dev/null
@@ -1,13 +0,0 @@
-#############################
-# APEX module manifest.
-#
-/manifest\.json u:object_r:system_file:s0
-
-#############################
-# System files
-#
-(/.*)? u:object_r:system_file:s0
-/bin/dex2oat(d)? u:object_r:dex2oat_exec:s0
-/bin/dexoptanalyzer(d)? u:object_r:dexoptanalyzer_exec:s0
-/bin/profman(d)? u:object_r:profman_exec:s0
-/lib(64)?(/.*)? u:object_r:system_lib_file:s0
diff --git a/compiler/driver/compiler_options.cc b/compiler/driver/compiler_options.cc
index be8e10e..685cde3 100644
--- a/compiler/driver/compiler_options.cc
+++ b/compiler/driver/compiler_options.cc
@@ -45,8 +45,8 @@
dex_files_for_oat_file_(),
image_classes_(),
boot_image_(false),
- core_image_(false),
app_image_(false),
+ compiling_with_core_image_(false),
baseline_(false),
debuggable_(false),
generate_debug_info_(kDefaultGenerateDebugInfo),
diff --git a/compiler/driver/compiler_options.h b/compiler/driver/compiler_options.h
index 77f8482..2f4e542 100644
--- a/compiler/driver/compiler_options.h
+++ b/compiler/driver/compiler_options.h
@@ -198,13 +198,6 @@
return baseline_;
}
- // Are we compiling a core image (small boot image only used for ART testing)?
- bool IsCoreImage() const {
- // Ensure that `core_image_` => `boot_image_`.
- DCHECK(!core_image_ || boot_image_);
- return core_image_;
- }
-
// Are we compiling an app image?
bool IsAppImage() const {
return app_image_;
@@ -214,6 +207,13 @@
app_image_ = false;
}
+ // Returns whether we are compiling against a "core" image, which
+ // is an indicative we are running tests. The compiler will use that
+ // information for checking invariants.
+ bool CompilingWithCoreImage() const {
+ return compiling_with_core_image_;
+ }
+
// Should the code be compiled as position independent?
bool GetCompilePic() const {
return compile_pic_;
@@ -357,8 +357,8 @@
HashSet<std::string> image_classes_;
bool boot_image_;
- bool core_image_;
bool app_image_;
+ bool compiling_with_core_image_;
bool baseline_;
bool debuggable_;
bool generate_debug_info_;
diff --git a/compiler/jit/jit_compiler.cc b/compiler/jit/jit_compiler.cc
index f22f61f..bb35065 100644
--- a/compiler/jit/jit_compiler.cc
+++ b/compiler/jit/jit_compiler.cc
@@ -90,10 +90,11 @@
// Special case max code units for inlining, whose default is "unset" (implictly
// meaning no limit). Do this before parsing the actual passed options.
compiler_options_->SetInlineMaxCodeUnits(CompilerOptions::kDefaultInlineMaxCodeUnits);
+ Runtime* runtime = Runtime::Current();
{
std::string error_msg;
- if (!compiler_options_->ParseCompilerOptions(Runtime::Current()->GetCompilerOptions(),
- true /* ignore_unrecognized */,
+ if (!compiler_options_->ParseCompilerOptions(runtime->GetCompilerOptions(),
+ /*ignore_unrecognized=*/ true,
&error_msg)) {
LOG(FATAL) << error_msg;
UNREACHABLE();
@@ -103,7 +104,7 @@
compiler_options_->SetNonPic();
// Set debuggability based on the runtime value.
- compiler_options_->SetDebuggable(Runtime::Current()->IsJavaDebuggable());
+ compiler_options_->SetDebuggable(runtime->IsJavaDebuggable());
const InstructionSet instruction_set = compiler_options_->GetInstructionSet();
if (kRuntimeISA == InstructionSet::kArm) {
@@ -112,7 +113,7 @@
DCHECK_EQ(instruction_set, kRuntimeISA);
}
std::unique_ptr<const InstructionSetFeatures> instruction_set_features;
- for (const StringPiece option : Runtime::Current()->GetCompilerOptions()) {
+ for (const StringPiece option : runtime->GetCompilerOptions()) {
VLOG(compiler) << "JIT compiler option " << option;
std::string error_msg;
if (option.starts_with("--instruction-set-variant=")) {
@@ -144,6 +145,8 @@
instruction_set_features = InstructionSetFeatures::FromCppDefines();
}
compiler_options_->instruction_set_features_ = std::move(instruction_set_features);
+ compiler_options_->compiling_with_core_image_ =
+ CompilerDriver::IsCoreImageFilename(runtime->GetImageLocation());
compiler_driver_.reset(new CompilerDriver(
compiler_options_.get(),
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 7dcf289..fba4da6 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -3497,6 +3497,27 @@
}
}
+void InstructionCodeGeneratorX86::RemByPowerOfTwo(HRem* instruction) {
+ LocationSummary* locations = instruction->GetLocations();
+ Location second = locations->InAt(1);
+
+ Register out = locations->Out().AsRegister<Register>();
+ Register numerator = locations->InAt(0).AsRegister<Register>();
+
+ int32_t imm = Int64FromConstant(second.GetConstant());
+ DCHECK(IsPowerOfTwo(AbsOrMin(imm)));
+ uint32_t abs_imm = static_cast<uint32_t>(AbsOrMin(imm));
+
+ Register tmp = locations->GetTemp(0).AsRegister<Register>();
+ NearLabel done;
+ __ movl(out, numerator);
+ __ andl(out, Immediate(abs_imm-1));
+ __ j(Condition::kZero, &done);
+ __ leal(tmp, Address(out, static_cast<int32_t>(~(abs_imm-1))));
+ __ testl(numerator, numerator);
+ __ cmovl(Condition::kLess, out, tmp);
+ __ Bind(&done);
+}
void InstructionCodeGeneratorX86::DivByPowerOfTwo(HDiv* instruction) {
LocationSummary* locations = instruction->GetLocations();
@@ -3610,8 +3631,12 @@
// Do not generate anything for 0. DivZeroCheck would forbid any generated code.
} else if (imm == 1 || imm == -1) {
DivRemOneOrMinusOne(instruction);
- } else if (is_div && IsPowerOfTwo(AbsOrMin(imm))) {
- DivByPowerOfTwo(instruction->AsDiv());
+ } else if (IsPowerOfTwo(AbsOrMin(imm))) {
+ if (is_div) {
+ DivByPowerOfTwo(instruction->AsDiv());
+ } else {
+ RemByPowerOfTwo(instruction->AsRem());
+ }
} else {
DCHECK(imm <= -2 || imm >= 2);
GenerateDivRemWithAnyConstant(instruction);
diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h
index 1e49403..deeef88 100644
--- a/compiler/optimizing/code_generator_x86.h
+++ b/compiler/optimizing/code_generator_x86.h
@@ -218,6 +218,7 @@
void GenerateDivRemIntegral(HBinaryOperation* instruction);
void DivRemOneOrMinusOne(HBinaryOperation* instruction);
void DivByPowerOfTwo(HDiv* instruction);
+ void RemByPowerOfTwo(HRem* instruction);
void GenerateDivRemWithAnyConstant(HBinaryOperation* instruction);
void GenerateRemFP(HRem* rem);
void HandleCondition(HCondition* condition);
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index d825390..14cff05 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -3560,7 +3560,40 @@
LOG(FATAL) << "Unexpected type for div by (-)1 " << instruction->GetResultType();
}
}
+void InstructionCodeGeneratorX86_64::RemByPowerOfTwo(HRem* instruction) {
+ LocationSummary* locations = instruction->GetLocations();
+ Location second = locations->InAt(1);
+ CpuRegister out = locations->Out().AsRegister<CpuRegister>();
+ CpuRegister numerator = locations->InAt(0).AsRegister<CpuRegister>();
+ int64_t imm = Int64FromConstant(second.GetConstant());
+ DCHECK(IsPowerOfTwo(AbsOrMin(imm)));
+ uint64_t abs_imm = AbsOrMin(imm);
+ CpuRegister tmp = locations->GetTemp(0).AsRegister<CpuRegister>();
+ if (instruction->GetResultType() == DataType::Type::kInt32) {
+ NearLabel done;
+ __ movl(out, numerator);
+ __ andl(out, Immediate(abs_imm-1));
+ __ j(Condition::kZero, &done);
+ __ leal(tmp, Address(out, static_cast<int32_t>(~(abs_imm-1))));
+ __ testl(numerator, numerator);
+ __ cmov(Condition::kLess, out, tmp, false);
+ __ Bind(&done);
+ } else {
+ DCHECK_EQ(instruction->GetResultType(), DataType::Type::kInt64);
+ codegen_->Load64BitValue(tmp, abs_imm - 1);
+ NearLabel done;
+
+ __ movq(out, numerator);
+ __ andq(out, tmp);
+ __ j(Condition::kZero, &done);
+ __ movq(tmp, numerator);
+ __ sarq(tmp, Immediate(63));
+ __ shlq(tmp, Immediate(WhichPowerOf2(abs_imm)));
+ __ orq(out, tmp);
+ __ Bind(&done);
+ }
+}
void InstructionCodeGeneratorX86_64::DivByPowerOfTwo(HDiv* instruction) {
LocationSummary* locations = instruction->GetLocations();
Location second = locations->InAt(1);
@@ -3737,8 +3770,12 @@
// Do not generate anything. DivZeroCheck would prevent any code to be executed.
} else if (imm == 1 || imm == -1) {
DivRemOneOrMinusOne(instruction);
- } else if (instruction->IsDiv() && IsPowerOfTwo(AbsOrMin(imm))) {
- DivByPowerOfTwo(instruction->AsDiv());
+ } else if (IsPowerOfTwo(AbsOrMin(imm))) {
+ if (is_div) {
+ DivByPowerOfTwo(instruction->AsDiv());
+ } else {
+ RemByPowerOfTwo(instruction->AsRem());
+ }
} else {
DCHECK(imm <= -2 || imm >= 2);
GenerateDivRemWithAnyConstant(instruction);
diff --git a/compiler/optimizing/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h
index 72c4fd4..f74e130 100644
--- a/compiler/optimizing/code_generator_x86_64.h
+++ b/compiler/optimizing/code_generator_x86_64.h
@@ -215,6 +215,7 @@
void GenerateRemFP(HRem* rem);
void DivRemOneOrMinusOne(HBinaryOperation* instruction);
void DivByPowerOfTwo(HDiv* instruction);
+ void RemByPowerOfTwo(HRem* instruction);
void GenerateDivRemWithAnyConstant(HBinaryOperation* instruction);
void GenerateDivRemIntegral(HBinaryOperation* instruction);
void HandleCondition(HCondition* condition);
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index c1daf95..d85bfd5 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -39,7 +39,6 @@
#include "mirror/object_array-alloc-inl.h"
#include "mirror/object_array-inl.h"
#include "nodes.h"
-#include "optimizing_compiler.h"
#include "reference_type_propagation.h"
#include "register_allocator_linear_scan.h"
#include "scoped_thread_state_change-inl.h"
@@ -151,13 +150,13 @@
// If we're compiling with a core image (which is only used for
// test purposes), honor inlining directives in method names:
- // - if a method's name contains the substring "$inline$", ensure
- // that this method is actually inlined;
// - if a method's name contains the substring "$noinline$", do not
- // inline that method.
+ // inline that method;
+ // - if a method's name contains the substring "$inline$", ensure
+ // that this method is actually inlined.
// We limit the latter to AOT compilation, as the JIT may or may not inline
// depending on the state of classes at runtime.
- const bool honor_noinline_directives = IsCompilingWithCoreImage();
+ const bool honor_noinline_directives = codegen_->GetCompilerOptions().CompilingWithCoreImage();
const bool honor_inline_directives =
honor_noinline_directives && Runtime::Current()->IsAotCompiler();
@@ -1737,6 +1736,21 @@
return (object != hint.Get()) ? handles->NewHandle(object) : hint;
}
+static bool CanEncodeInlinedMethodInStackMap(const DexFile& caller_dex_file, ArtMethod* callee)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ if (!Runtime::Current()->IsAotCompiler()) {
+ // JIT can always encode methods in stack maps.
+ return true;
+ }
+ if (IsSameDexFile(caller_dex_file, *callee->GetDexFile())) {
+ return true;
+ }
+ // TODO(ngeoffray): Support more AOT cases for inlining:
+ // - methods in multidex
+ // - methods in boot image for on-device non-PIC compilation.
+ return false;
+}
+
bool HInliner::TryBuildAndInlineHelper(HInvoke* invoke_instruction,
ArtMethod* resolved_method,
ReferenceTypeInfo receiver_type,
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index c9c1194..fe6abd4 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -1136,7 +1136,7 @@
}
if (kIsDebugBuild &&
- IsCompilingWithCoreImage() &&
+ compiler_driver->GetCompilerOptions().CompilingWithCoreImage() &&
IsInstructionSetSupported(compiler_driver->GetCompilerOptions().GetInstructionSet())) {
// For testing purposes, we put a special marker on method names
// that should be compiled with this compiler (when the
@@ -1234,30 +1234,11 @@
return new OptimizingCompiler(driver);
}
-bool IsCompilingWithCoreImage() {
- const std::string& image = Runtime::Current()->GetImageLocation();
- return CompilerDriver::IsCoreImageFilename(image);
-}
-
bool EncodeArtMethodInInlineInfo(ArtMethod* method ATTRIBUTE_UNUSED) {
// Note: the runtime is null only for unit testing.
return Runtime::Current() == nullptr || !Runtime::Current()->IsAotCompiler();
}
-bool CanEncodeInlinedMethodInStackMap(const DexFile& caller_dex_file, ArtMethod* callee) {
- if (!Runtime::Current()->IsAotCompiler()) {
- // JIT can always encode methods in stack maps.
- return true;
- }
- if (IsSameDexFile(caller_dex_file, *callee->GetDexFile())) {
- return true;
- }
- // TODO(ngeoffray): Support more AOT cases for inlining:
- // - methods in multidex
- // - methods in boot image for on-device non-PIC compilation.
- return false;
-}
-
bool OptimizingCompiler::JitCompile(Thread* self,
jit::JitCodeCache* code_cache,
ArtMethod* method,
diff --git a/compiler/optimizing/optimizing_compiler.h b/compiler/optimizing/optimizing_compiler.h
index 6ee9c70..f5279e8 100644
--- a/compiler/optimizing/optimizing_compiler.h
+++ b/compiler/optimizing/optimizing_compiler.h
@@ -29,14 +29,7 @@
Compiler* CreateOptimizingCompiler(CompilerDriver* driver);
-// Returns whether we are compiling against a "core" image, which
-// is an indicative we are running tests. The compiler will use that
-// information for checking invariants.
-bool IsCompilingWithCoreImage();
-
bool EncodeArtMethodInInlineInfo(ArtMethod* method);
-bool CanEncodeInlinedMethodInStackMap(const DexFile& caller_dex_file, ArtMethod* callee)
- REQUIRES_SHARED(Locks::mutator_lock_);
} // namespace art
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index d901c01..dc123e4 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -732,11 +732,6 @@
compiler_options_->boot_image_ = !image_filenames_.empty();
compiler_options_->app_image_ = app_image_fd_ != -1 || !app_image_file_name_.empty();
- if (IsBootImage() && image_filenames_.size() == 1) {
- const std::string& boot_image_filename = image_filenames_[0];
- compiler_options_->core_image_ = CompilerDriver::IsCoreImageFilename(boot_image_filename);
- }
-
if (IsAppImage() && IsBootImage()) {
Usage("Can't have both --image and (--app-image-fd or --app-image-file)");
}
@@ -951,6 +946,9 @@
}
}
compiler_options_->passes_to_run_ = passes_to_run_.get();
+ compiler_options_->compiling_with_core_image_ =
+ !boot_image_filename_.empty() &&
+ CompilerDriver::IsCoreImageFilename(boot_image_filename_);
}
static bool SupportsDeterministicCompilation() {
@@ -1055,9 +1053,6 @@
oss << argv[i];
}
key_value_store_->Put(OatHeader::kDex2OatCmdLineKey, oss.str());
- oss.str(""); // Reset.
- oss << kRuntimeISA;
- key_value_store_->Put(OatHeader::kDex2OatHostKey, oss.str());
}
key_value_store_->Put(
OatHeader::kDebuggableKey,
diff --git a/dex2oat/linker/image_writer.cc b/dex2oat/linker/image_writer.cc
index 5ca7f07..2b2b029 100644
--- a/dex2oat/linker/image_writer.cc
+++ b/dex2oat/linker/image_writer.cc
@@ -2670,10 +2670,8 @@
void ImageWriter::FixupPointerArray(mirror::Object* dst,
mirror::PointerArray* arr,
- mirror::Class* klass,
Bin array_type) {
- CHECK(klass->IsArrayClass());
- CHECK(arr->IsIntArray() || arr->IsLongArray()) << klass->PrettyClass() << " " << arr;
+ CHECK(arr->IsIntArray() || arr->IsLongArray()) << arr->GetClass()->PrettyClass() << " " << arr;
// Fixup int and long pointers for the ArtMethod or ArtField arrays.
const size_t num_elements = arr->GetLength();
CopyAndFixupReference(
@@ -2879,13 +2877,12 @@
if (kUseBakerReadBarrier) {
orig->AssertReadBarrierState();
}
- auto* klass = orig->GetClass();
- if (klass->IsIntArrayClass() || klass->IsLongArrayClass()) {
+ if (orig->IsIntArray() || orig->IsLongArray()) {
// Is this a native pointer array?
auto it = pointer_arrays_.find(down_cast<mirror::PointerArray*>(orig));
if (it != pointer_arrays_.end()) {
// Should only need to fixup every pointer array exactly once.
- FixupPointerArray(copy, down_cast<mirror::PointerArray*>(orig), klass, it->second);
+ FixupPointerArray(copy, down_cast<mirror::PointerArray*>(orig), it->second);
pointer_arrays_.erase(it);
return;
}
@@ -2895,6 +2892,7 @@
} else {
ObjPtr<mirror::ObjectArray<mirror::Class>> class_roots =
Runtime::Current()->GetClassLinker()->GetClassRoots();
+ ObjPtr<mirror::Class> klass = orig->GetClass();
if (klass == GetClassRoot<mirror::Method>(class_roots) ||
klass == GetClassRoot<mirror::Constructor>(class_roots)) {
// Need to go update the ArtMethod.
diff --git a/dex2oat/linker/image_writer.h b/dex2oat/linker/image_writer.h
index 06c694c..ccd529a 100644
--- a/dex2oat/linker/image_writer.h
+++ b/dex2oat/linker/image_writer.h
@@ -541,7 +541,6 @@
REQUIRES_SHARED(Locks::mutator_lock_);
void FixupPointerArray(mirror::Object* dst,
mirror::PointerArray* arr,
- mirror::Class* klass,
Bin array_type)
REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/openjdkjvmti/deopt_manager.cc b/openjdkjvmti/deopt_manager.cc
index 8bac38a..d456d83 100644
--- a/openjdkjvmti/deopt_manager.cc
+++ b/openjdkjvmti/deopt_manager.cc
@@ -139,6 +139,9 @@
// OnLoad since the runtime hasn't started up sufficiently. This is only expected to happen
// on userdebug/eng builds.
LOG(INFO) << "Attempting to start jit for openjdkjvmti plugin.";
+ // Note: use rwx allowed = true, because if this is the system server, we will not be
+ // allowed to allocate any JIT code cache, anyways.
+ runtime->CreateJitCodeCache(/*rwx_memory_allowed=*/true);
runtime->CreateJit();
if (runtime->GetJit() == nullptr) {
LOG(WARNING) << "Could not start jit for openjdkjvmti plugin. This process might be "
diff --git a/openjdkjvmti/events.cc b/openjdkjvmti/events.cc
index 48df53a..a96436e 100644
--- a/openjdkjvmti/events.cc
+++ b/openjdkjvmti/events.cc
@@ -32,6 +32,7 @@
#include "events-inl.h"
#include <array>
+#include <sys/time.h>
#include "art_field-inl.h"
#include "art_jvmti.h"
@@ -56,6 +57,7 @@
#include "thread-inl.h"
#include "thread_list.h"
#include "ti_phase.h"
+#include "well_known_classes.h"
namespace openjdkjvmti {
@@ -410,14 +412,103 @@
EventHandler* handler_;
};
-static void SetupMonitorListener(art::MonitorCallback* listener, bool enable) {
+class JvmtiParkListener : public art::ParkCallback {
+ public:
+ explicit JvmtiParkListener(EventHandler* handler) : handler_(handler) {}
+
+ void ThreadParkStart(bool is_absolute, int64_t timeout)
+ override REQUIRES_SHARED(art::Locks::mutator_lock_) {
+ if (handler_->IsEventEnabledAnywhere(ArtJvmtiEvent::kMonitorWait)) {
+ art::Thread* self = art::Thread::Current();
+ art::JNIEnvExt* jnienv = self->GetJniEnv();
+ art::ArtField* parkBlockerField = art::jni::DecodeArtField(
+ art::WellKnownClasses::java_lang_Thread_parkBlocker);
+ art::ObjPtr<art::mirror::Object> blocker_obj = parkBlockerField->GetObj(self->GetPeer());
+ if (blocker_obj.IsNull()) {
+ blocker_obj = self->GetPeer();
+ }
+ int64_t timeout_ms;
+ if (!is_absolute) {
+ if (timeout == 0) {
+ timeout_ms = 0;
+ } else {
+ timeout_ms = timeout / 1000000;
+ if (timeout_ms == 0) {
+ // If we were instructed to park for a nonzero number of nanoseconds, but not enough
+ // to be a full millisecond, round up to 1 ms. A nonzero park() call will return
+ // soon, but a 0 wait or park call will wait indefinitely.
+ timeout_ms = 1;
+ }
+ }
+ } else {
+ struct timeval tv;
+ gettimeofday(&tv, (struct timezone *) nullptr);
+ int64_t now = tv.tv_sec * 1000LL + tv.tv_usec / 1000;
+ if (now < timeout) {
+ timeout_ms = timeout - now;
+ } else {
+ // Waiting for 0 ms is an indefinite wait; parking until a time in
+ // the past or the current time will return immediately, so emulate
+ // the shortest possible wait event.
+ timeout_ms = 1;
+ }
+ }
+ ScopedLocalRef<jobject> blocker(jnienv, AddLocalRef<jobject>(jnienv, blocker_obj.Ptr()));
+ RunEventCallback<ArtJvmtiEvent::kMonitorWait>(
+ handler_,
+ self,
+ jnienv,
+ blocker.get(),
+ static_cast<jlong>(timeout_ms));
+ }
+ }
+
+
+ // Our interpretation of the spec is that the JVMTI_EVENT_MONITOR_WAITED will be sent immediately
+ // after a thread has woken up from a sleep caused by a call to Object#wait. If the thread will
+ // never go to sleep (due to not having the lock, having bad arguments, or having an exception
+ // propogated from JVMTI_EVENT_MONITOR_WAIT) we will not send this event.
+ //
+ // This does not fully match the RI semantics. Specifically, we will not send the
+ // JVMTI_EVENT_MONITOR_WAITED event in one situation where the RI would, there was an exception in
+ // the JVMTI_EVENT_MONITOR_WAIT event but otherwise the call was fine. In that case the RI would
+ // send this event and return without going to sleep.
+ //
+ // See b/65558434 for more discussion.
+ void ThreadParkFinished(bool timeout) override REQUIRES_SHARED(art::Locks::mutator_lock_) {
+ if (handler_->IsEventEnabledAnywhere(ArtJvmtiEvent::kMonitorWaited)) {
+ art::Thread* self = art::Thread::Current();
+ art::JNIEnvExt* jnienv = self->GetJniEnv();
+ art::ArtField* parkBlockerField = art::jni::DecodeArtField(
+ art::WellKnownClasses::java_lang_Thread_parkBlocker);
+ art::ObjPtr<art::mirror::Object> blocker_obj = parkBlockerField->GetObj(self->GetPeer());
+ if (blocker_obj.IsNull()) {
+ blocker_obj = self->GetPeer();
+ }
+ ScopedLocalRef<jobject> blocker(jnienv, AddLocalRef<jobject>(jnienv, blocker_obj.Ptr()));
+ RunEventCallback<ArtJvmtiEvent::kMonitorWaited>(
+ handler_,
+ self,
+ jnienv,
+ blocker.get(),
+ static_cast<jboolean>(timeout));
+ }
+ }
+
+ private:
+ EventHandler* handler_;
+};
+
+static void SetupMonitorListener(art::MonitorCallback* monitor_listener, art::ParkCallback* park_listener, bool enable) {
// We must not hold the mutator lock here, but if we're in FastJNI, for example, we might. For
// now, do a workaround: (possibly) acquire and release.
art::ScopedObjectAccess soa(art::Thread::Current());
if (enable) {
- art::Runtime::Current()->GetRuntimeCallbacks()->AddMonitorCallback(listener);
+ art::Runtime::Current()->GetRuntimeCallbacks()->AddMonitorCallback(monitor_listener);
+ art::Runtime::Current()->GetRuntimeCallbacks()->AddParkCallback(park_listener);
} else {
- art::Runtime::Current()->GetRuntimeCallbacks()->RemoveMonitorCallback(listener);
+ art::Runtime::Current()->GetRuntimeCallbacks()->RemoveMonitorCallback(monitor_listener);
+ art::Runtime::Current()->GetRuntimeCallbacks()->RemoveParkCallback(park_listener);
}
}
@@ -1053,7 +1144,7 @@
case ArtJvmtiEvent::kMonitorWait:
case ArtJvmtiEvent::kMonitorWaited:
if (!OtherMonitorEventsEnabledAnywhere(event)) {
- SetupMonitorListener(monitor_listener_.get(), enable);
+ SetupMonitorListener(monitor_listener_.get(), park_listener_.get(), enable);
}
return;
default:
@@ -1204,6 +1295,7 @@
gc_pause_listener_.reset(new JvmtiGcPauseListener(this));
method_trace_listener_.reset(new JvmtiMethodTraceListener(this));
monitor_listener_.reset(new JvmtiMonitorListener(this));
+ park_listener_.reset(new JvmtiParkListener(this));
}
EventHandler::~EventHandler() {
diff --git a/openjdkjvmti/events.h b/openjdkjvmti/events.h
index 9f91a08..abb15cc 100644
--- a/openjdkjvmti/events.h
+++ b/openjdkjvmti/events.h
@@ -35,6 +35,7 @@
class JvmtiGcPauseListener;
class JvmtiMethodTraceListener;
class JvmtiMonitorListener;
+class JvmtiParkListener;
// an enum for ArtEvents. This differs from the JVMTI events only in that we distinguish between
// retransformation capable and incapable loading
@@ -331,6 +332,7 @@
std::unique_ptr<JvmtiGcPauseListener> gc_pause_listener_;
std::unique_ptr<JvmtiMethodTraceListener> method_trace_listener_;
std::unique_ptr<JvmtiMonitorListener> monitor_listener_;
+ std::unique_ptr<JvmtiParkListener> park_listener_;
// True if frame pop has ever been enabled. Since we store pointers to stack frames we need to
// continue to listen to this event even if it has been disabled.
diff --git a/runtime/cha.cc b/runtime/cha.cc
index de4aebe..8e06fda 100644
--- a/runtime/cha.cc
+++ b/runtime/cha.cc
@@ -115,7 +115,7 @@
// if they have SingleImplementations methods defined by 'klass'.
// Skip all virtual methods that do not override methods from super class since they cannot be
// SingleImplementations for anything.
- int32_t vtbl_size = super->GetVTableLength<kDefaultVerifyFlags, kWithoutReadBarrier>();
+ int32_t vtbl_size = super->GetVTableLength<kDefaultVerifyFlags>();
ObjPtr<mirror::ClassLoader> loader =
klass->GetClassLoader<kDefaultVerifyFlags, kWithoutReadBarrier>();
for (int vtbl_index = 0; vtbl_index < vtbl_size; ++vtbl_index) {
@@ -131,7 +131,7 @@
// so start with a superclass and move up looking into a corresponding vtbl slot.
for (ObjPtr<mirror::Class> super_it = super;
super_it != nullptr &&
- super_it->GetVTableLength<kDefaultVerifyFlags, kWithoutReadBarrier>() > vtbl_index;
+ super_it->GetVTableLength<kDefaultVerifyFlags>() > vtbl_index;
super_it = super_it->GetSuperClass<kDefaultVerifyFlags, kWithoutReadBarrier>()) {
// Skip superclasses that are also going to be unloaded.
ObjPtr<mirror::ClassLoader> super_loader = super_it->
@@ -158,7 +158,7 @@
// Check all possible interface methods too.
ObjPtr<mirror::IfTable> iftable = klass->GetIfTable<kDefaultVerifyFlags, kWithoutReadBarrier>();
- const size_t ifcount = klass->GetIfTableCount<kDefaultVerifyFlags, kWithoutReadBarrier>();
+ const size_t ifcount = klass->GetIfTableCount<kDefaultVerifyFlags>();
for (size_t i = 0; i < ifcount; ++i) {
ObjPtr<mirror::Class> interface =
iftable->GetInterface<kDefaultVerifyFlags, kWithoutReadBarrier>(i);
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 67513f9..cc4f56c 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -3112,7 +3112,7 @@
return (jit == nullptr) || !jit->GetCodeCache()->ContainsPc(quick_code);
}
- if (runtime->IsNativeDebuggable()) {
+ if (runtime->IsNativeDebuggableZygoteOK()) {
DCHECK(runtime->UseJitCompilation() && runtime->GetJit()->JitAtFirstUse());
// If we are doing native debugging, ignore application's AOT code,
// since we want to JIT it (at first use) with extra stackmaps for native
diff --git a/runtime/class_loader_context.cc b/runtime/class_loader_context.cc
index de9fe22..0bae60a 100644
--- a/runtime/class_loader_context.cc
+++ b/runtime/class_loader_context.cc
@@ -338,6 +338,7 @@
// no dex files. So that we can distinguish the real failures...
const ArtDexFileLoader dex_file_loader;
std::vector<ClassLoaderInfo*> work_list;
+ CHECK(class_loader_chain_ != nullptr);
work_list.push_back(class_loader_chain_.get());
while (!work_list.empty()) {
ClassLoaderInfo* info = work_list.back();
@@ -908,7 +909,9 @@
// collision check.
if (expected_context.special_shared_library_) {
// Special case where we are the only entry in the class path.
- if (class_loader_chain_->parent == nullptr && class_loader_chain_->classpath.size() == 0) {
+ if (class_loader_chain_ != nullptr &&
+ class_loader_chain_->parent == nullptr &&
+ class_loader_chain_->classpath.size() == 0) {
return VerificationResult::kVerifies;
}
return VerificationResult::kForcedToSkipChecks;
diff --git a/runtime/class_loader_context_test.cc b/runtime/class_loader_context_test.cc
index cb3dc65..f3e2ac0 100644
--- a/runtime/class_loader_context_test.cc
+++ b/runtime/class_loader_context_test.cc
@@ -735,6 +735,17 @@
ClassLoaderContext::VerificationResult::kMismatch);
}
+TEST_F(ClassLoaderContextTest, VerifyClassLoaderContextMatchSpecial) {
+ std::string context_spec = "&";
+ std::unique_ptr<ClassLoaderContext> context = ParseContextWithChecksums(context_spec);
+ // Pretend that we successfully open the dex files to pass the DCHECKS.
+ // (as it's much easier to test all the corner cases without relying on actual dex files).
+ PretendContextOpenedDexFiles(context.get());
+
+ ASSERT_EQ(context->VerifyClassLoaderContextMatch(context_spec),
+ ClassLoaderContext::VerificationResult::kForcedToSkipChecks);
+}
+
TEST_F(ClassLoaderContextTest, VerifyClassLoaderContextMatchWithSL) {
std::string context_spec =
"PCL[a.dex*123:b.dex*456]{PCL[d.dex*321];PCL[e.dex*654]#PCL[f.dex*098:g.dex*999]}"
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index b46abfb..0766999 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -832,7 +832,7 @@
reinterpret_cast<uintptr_t>(array) + kObjectAlignment);
// If the bit is not set then the contents have not yet been updated.
if (!visited_->Test(contents_bit)) {
- array->Fixup<kVerifyNone, kWithoutReadBarrier>(array, pointer_size_, visitor);
+ array->Fixup<kVerifyNone>(array, pointer_size_, visitor);
visited_->Set(contents_bit);
}
}
@@ -1884,7 +1884,7 @@
}
auto* iftable = klass->GetIfTable<kVerifyNone, kWithoutReadBarrier>();
if (iftable != nullptr) {
- int32_t ifcount = klass->GetIfTableCount<kVerifyNone, kWithoutReadBarrier>();
+ int32_t ifcount = klass->GetIfTableCount<kVerifyNone>();
for (int32_t i = 0; i != ifcount; ++i) {
mirror::PointerArray* unpatched_ifarray =
iftable->GetMethodArrayOrNull<kVerifyNone, kWithoutReadBarrier>(i);
diff --git a/runtime/mirror/array-inl.h b/runtime/mirror/array-inl.h
index 4427332..a6a5ba2 100644
--- a/runtime/mirror/array-inl.h
+++ b/runtime/mirror/array-inl.h
@@ -224,16 +224,14 @@
}
}
-template<typename T, VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption>
+template<typename T, VerifyObjectFlags kVerifyFlags>
inline T PointerArray::GetElementPtrSize(uint32_t idx, PointerSize ptr_size) {
// C style casts here since we sometimes have T be a pointer, or sometimes an integer
// (for stack traces).
if (ptr_size == PointerSize::k64) {
- return (T)static_cast<uintptr_t>(
- AsLongArray<kVerifyFlags, kReadBarrierOption>()->GetWithoutChecks(idx));
+ return (T)static_cast<uintptr_t>(AsLongArray<kVerifyFlags>()->GetWithoutChecks(idx));
}
- return (T)static_cast<uintptr_t>(static_cast<uint32_t>(
- AsIntArray<kVerifyFlags, kReadBarrierOption>()->GetWithoutChecks(idx)));
+ return (T)static_cast<uintptr_t>(AsIntArray<kVerifyFlags>()->GetWithoutChecks(idx));
}
template<bool kTransactionActive, bool kUnchecked>
@@ -255,12 +253,12 @@
ptr_size);
}
-template <VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption, typename Visitor>
+template <VerifyObjectFlags kVerifyFlags, typename Visitor>
inline void PointerArray::Fixup(mirror::PointerArray* dest,
PointerSize pointer_size,
const Visitor& visitor) {
for (size_t i = 0, count = GetLength(); i < count; ++i) {
- void* ptr = GetElementPtrSize<void*, kVerifyFlags, kReadBarrierOption>(i, pointer_size);
+ void* ptr = GetElementPtrSize<void*, kVerifyFlags>(i, pointer_size);
void* new_ptr = visitor(ptr);
if (ptr != new_ptr) {
dest->SetElementPtrSize<false, true>(i, new_ptr, pointer_size);
diff --git a/runtime/mirror/array.h b/runtime/mirror/array.h
index 7211f30..8816c61 100644
--- a/runtime/mirror/array.h
+++ b/runtime/mirror/array.h
@@ -193,9 +193,7 @@
// Either an IntArray or a LongArray.
class PointerArray : public Array {
public:
- template<typename T,
- VerifyObjectFlags kVerifyFlags = kVerifyNone,
- ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
+ template<typename T, VerifyObjectFlags kVerifyFlags = kVerifyNone>
T GetElementPtrSize(uint32_t idx, PointerSize ptr_size)
REQUIRES_SHARED(Locks::mutator_lock_);
@@ -216,9 +214,7 @@
// Fixup the pointers in the dest arrays by passing our pointers through the visitor. Only copies
// to dest if visitor(source_ptr) != source_ptr.
- template <VerifyObjectFlags kVerifyFlags = kVerifyNone,
- ReadBarrierOption kReadBarrierOption = kWithReadBarrier,
- typename Visitor>
+ template <VerifyObjectFlags kVerifyFlags = kVerifyNone, typename Visitor>
void Fixup(mirror::PointerArray* dest, PointerSize pointer_size, const Visitor& visitor)
REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h
index 9a4130d..6b9ba8c 100644
--- a/runtime/mirror/class-inl.h
+++ b/runtime/mirror/class-inl.h
@@ -294,16 +294,20 @@
}
inline bool Class::HasVTable() {
- return GetVTable() != nullptr || ShouldHaveEmbeddedVTable();
+ // No read barrier is needed for comparing with null.
+ return GetVTable<kDefaultVerifyFlags, kWithoutReadBarrier>() != nullptr ||
+ ShouldHaveEmbeddedVTable();
}
-template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption>
+template<VerifyObjectFlags kVerifyFlags>
inline int32_t Class::GetVTableLength() {
if (ShouldHaveEmbeddedVTable<kVerifyFlags>()) {
return GetEmbeddedVTableLength();
}
- return GetVTable<kVerifyFlags, kReadBarrierOption>() != nullptr ?
- GetVTable<kVerifyFlags, kReadBarrierOption>()->GetLength() : 0;
+ // We do not need a read barrier here as the length is constant,
+ // both from-space and to-space vtables shall yield the same result.
+ ObjPtr<PointerArray> vtable = GetVTable<kVerifyFlags, kWithoutReadBarrier>();
+ return vtable != nullptr ? vtable->GetLength() : 0;
}
template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption>
@@ -311,10 +315,9 @@
if (ShouldHaveEmbeddedVTable<kVerifyFlags>()) {
return GetEmbeddedVTableEntry(i, pointer_size);
}
- auto* vtable = GetVTable<kVerifyFlags, kReadBarrierOption>();
+ ObjPtr<PointerArray> vtable = GetVTable<kVerifyFlags, kReadBarrierOption>();
DCHECK(vtable != nullptr);
- return vtable->template GetElementPtrSize<ArtMethod*, kVerifyFlags, kReadBarrierOption>(
- i, pointer_size);
+ return vtable->GetElementPtrSize<ArtMethod*, kVerifyFlags>(i, pointer_size);
}
template<VerifyObjectFlags kVerifyFlags>
@@ -624,9 +627,11 @@
return ret.Ptr();
}
-template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption>
+template<VerifyObjectFlags kVerifyFlags>
inline int32_t Class::GetIfTableCount() {
- return GetIfTable<kVerifyFlags, kReadBarrierOption>()->Count();
+ // We do not need a read barrier here as the length is constant,
+ // both from-space and to-space iftables shall yield the same result.
+ return GetIfTable<kVerifyFlags, kWithoutReadBarrier>()->Count();
}
inline void Class::SetIfTable(ObjPtr<IfTable> new_iftable) {
@@ -970,7 +975,17 @@
// We do not need a read barrier here as the primitive type is constant,
// both from-space and to-space component type classes shall yield the same result.
ObjPtr<Class> const component_type = GetComponentType<kVerifyFlags, kWithoutReadBarrier>();
- return component_type != nullptr && !component_type->IsPrimitive<kVerifyFlags>();
+ constexpr VerifyObjectFlags kNewFlags = RemoveThisFlags(kVerifyFlags);
+ return component_type != nullptr && !component_type->IsPrimitive<kNewFlags>();
+}
+
+template<VerifyObjectFlags kVerifyFlags>
+bool Class::IsPrimitiveArray() {
+ // We do not need a read barrier here as the primitive type is constant,
+ // both from-space and to-space component type classes shall yield the same result.
+ ObjPtr<Class> const component_type = GetComponentType<kVerifyFlags, kWithoutReadBarrier>();
+ constexpr VerifyObjectFlags kNewFlags = RemoveThisFlags(kVerifyFlags);
+ return component_type != nullptr && component_type->IsPrimitive<kNewFlags>();
}
inline bool Class::IsAssignableFrom(ObjPtr<Class> src) {
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index 74fca54..bb54b3d 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -422,13 +422,6 @@
return GetPrimitiveType<kVerifyFlags>() == Primitive::kPrimVoid;
}
- template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
- bool IsPrimitiveArray() REQUIRES_SHARED(Locks::mutator_lock_) {
- return IsArrayClass<kVerifyFlags>() &&
- GetComponentType<static_cast<VerifyObjectFlags>(kVerifyFlags & ~kVerifyThis)>()->
- IsPrimitive();
- }
-
// Depth of class from java.lang.Object
uint32_t Depth() REQUIRES_SHARED(Locks::mutator_lock_);
@@ -466,7 +459,8 @@
}
bool IsObjectClass() REQUIRES_SHARED(Locks::mutator_lock_) {
- return !IsPrimitive() && GetSuperClass() == nullptr;
+ // No read barrier is needed for comparing with null.
+ return !IsPrimitive() && GetSuperClass<kDefaultVerifyFlags, kWithoutReadBarrier>() == nullptr;
}
bool IsInstantiableNonArray() REQUIRES_SHARED(Locks::mutator_lock_) {
@@ -485,18 +479,7 @@
ALWAYS_INLINE bool IsObjectArrayClass() REQUIRES_SHARED(Locks::mutator_lock_);
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
- bool IsIntArrayClass() REQUIRES_SHARED(Locks::mutator_lock_) {
- constexpr auto kNewFlags = static_cast<VerifyObjectFlags>(kVerifyFlags & ~kVerifyThis);
- auto* component_type = GetComponentType<kVerifyFlags>();
- return component_type != nullptr && component_type->template IsPrimitiveInt<kNewFlags>();
- }
-
- template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
- bool IsLongArrayClass() REQUIRES_SHARED(Locks::mutator_lock_) {
- constexpr auto kNewFlags = static_cast<VerifyObjectFlags>(kVerifyFlags & ~kVerifyThis);
- auto* component_type = GetComponentType<kVerifyFlags>();
- return component_type != nullptr && component_type->template IsPrimitiveLong<kNewFlags>();
- }
+ bool IsPrimitiveArray() REQUIRES_SHARED(Locks::mutator_lock_);
// Creates a raw object instance but does not invoke the default constructor.
template<bool kIsInstrumented, bool kCheckAddFinalizer = true>
@@ -633,7 +616,8 @@
void SetSuperClass(ObjPtr<Class> new_super_class) REQUIRES_SHARED(Locks::mutator_lock_);
bool HasSuperClass() REQUIRES_SHARED(Locks::mutator_lock_) {
- return GetSuperClass() != nullptr;
+ // No read barrier is needed for comparing with null.
+ return GetSuperClass<kDefaultVerifyFlags, kWithoutReadBarrier>() != nullptr;
}
static constexpr MemberOffset SuperClassOffset() {
@@ -812,8 +796,7 @@
static MemberOffset EmbeddedVTableEntryOffset(uint32_t i, PointerSize pointer_size);
- template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
- ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
+ template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
int32_t GetVTableLength() REQUIRES_SHARED(Locks::mutator_lock_);
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
@@ -948,8 +931,7 @@
return (GetAccessFlags() & kAccRecursivelyInitialized) != 0;
}
- template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
- ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
+ template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
ALWAYS_INLINE int32_t GetIfTableCount() REQUIRES_SHARED(Locks::mutator_lock_);
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
@@ -1216,7 +1198,8 @@
// Returns true if the class loader is null, ie the class loader is the boot strap class loader.
bool IsBootStrapClassLoaded() REQUIRES_SHARED(Locks::mutator_lock_) {
- return GetClassLoader() == nullptr;
+ // No read barrier is needed for comparing with null.
+ return GetClassLoader<kDefaultVerifyFlags, kWithoutReadBarrier>() == nullptr;
}
static size_t ImTableEntrySize(PointerSize pointer_size) {
diff --git a/runtime/mirror/class_ext-inl.h b/runtime/mirror/class_ext-inl.h
index feaac85..8d68dc9 100644
--- a/runtime/mirror/class_ext-inl.h
+++ b/runtime/mirror/class_ext-inl.h
@@ -32,9 +32,7 @@
}
int32_t len = arr->GetLength();
for (int32_t i = 0; i < len; i++) {
- ArtMethod* method = arr->GetElementPtrSize<ArtMethod*,
- kDefaultVerifyFlags,
- kReadBarrierOption>(i, pointer_size);
+ ArtMethod* method = arr->GetElementPtrSize<ArtMethod*, kDefaultVerifyFlags>(i, pointer_size);
if (method != nullptr) {
method->VisitRoots<kReadBarrierOption>(visitor, pointer_size);
}
diff --git a/runtime/mirror/object-inl.h b/runtime/mirror/object-inl.h
index 8ae79a8..2c2ad9b 100644
--- a/runtime/mirror/object-inl.h
+++ b/runtime/mirror/object-inl.h
@@ -156,7 +156,7 @@
inline bool Object::IsObjectArray() {
// We do not need a read barrier here as the primitive type is constant,
// both from-space and to-space component type classes shall yield the same result.
- constexpr auto kNewFlags = RemoveThisFlags(kVerifyFlags);
+ constexpr VerifyObjectFlags kNewFlags = RemoveThisFlags(kVerifyFlags);
return IsArrayInstance<kVerifyFlags>() &&
!GetClass<kNewFlags, kWithoutReadBarrier>()->
template GetComponentType<kNewFlags, kWithoutReadBarrier>()->IsPrimitive();
@@ -192,113 +192,102 @@
return down_cast<Array*>(this);
}
+template<VerifyObjectFlags kVerifyFlags, Primitive::Type kType>
+ALWAYS_INLINE bool Object::IsSpecificPrimitiveArray() {
+ // We do not need a read barrier here as the primitive type is constant,
+ // both from-space and to-space component type classes shall yield the same result.
+ ObjPtr<Class> klass = GetClass<kVerifyFlags, kWithoutReadBarrier>();
+ constexpr VerifyObjectFlags kNewFlags = RemoveThisFlags(kVerifyFlags);
+ ObjPtr<Class> const component_type = klass->GetComponentType<kNewFlags, kWithoutReadBarrier>();
+ return component_type != nullptr &&
+ component_type->GetPrimitiveType<kNewFlags>() == kType;
+}
+
+template<VerifyObjectFlags kVerifyFlags>
+inline bool Object::IsBooleanArray() {
+ return IsSpecificPrimitiveArray<kVerifyFlags, Primitive::kPrimBoolean>();
+}
+
template<VerifyObjectFlags kVerifyFlags>
inline BooleanArray* Object::AsBooleanArray() {
- constexpr auto kNewFlags = RemoveThisFlags(kVerifyFlags);
- DCHECK(GetClass<kVerifyFlags>()->IsArrayClass());
- DCHECK(GetClass<kNewFlags>()->GetComponentType()->IsPrimitiveBoolean());
+ DCHECK(IsBooleanArray<kVerifyFlags>());
return down_cast<BooleanArray*>(this);
}
template<VerifyObjectFlags kVerifyFlags>
+inline bool Object::IsByteArray() {
+ return IsSpecificPrimitiveArray<kVerifyFlags, Primitive::kPrimByte>();
+}
+
+template<VerifyObjectFlags kVerifyFlags>
inline ByteArray* Object::AsByteArray() {
- constexpr auto kNewFlags = RemoveThisFlags(kVerifyFlags);
- DCHECK(GetClass<kVerifyFlags>()->IsArrayClass());
- DCHECK(GetClass<kNewFlags>()->template GetComponentType<kNewFlags>()->IsPrimitiveByte());
+ DCHECK(IsByteArray<kVerifyFlags>());
return down_cast<ByteArray*>(this);
}
template<VerifyObjectFlags kVerifyFlags>
-inline ByteArray* Object::AsByteSizedArray() {
- constexpr auto kNewFlags = RemoveThisFlags(kVerifyFlags);
- DCHECK(GetClass<kVerifyFlags>()->IsArrayClass());
- DCHECK(GetClass<kNewFlags>()->template GetComponentType<kNewFlags>()->IsPrimitiveByte() ||
- GetClass<kNewFlags>()->template GetComponentType<kNewFlags>()->IsPrimitiveBoolean());
- return down_cast<ByteArray*>(this);
+inline bool Object::IsCharArray() {
+ return IsSpecificPrimitiveArray<kVerifyFlags, Primitive::kPrimChar>();
}
template<VerifyObjectFlags kVerifyFlags>
inline CharArray* Object::AsCharArray() {
- constexpr auto kNewFlags = RemoveThisFlags(kVerifyFlags);
- DCHECK(GetClass<kVerifyFlags>()->IsArrayClass());
- DCHECK(GetClass<kNewFlags>()->template GetComponentType<kNewFlags>()->IsPrimitiveChar());
+ DCHECK(IsCharArray<kVerifyFlags>());
return down_cast<CharArray*>(this);
}
template<VerifyObjectFlags kVerifyFlags>
+inline bool Object::IsShortArray() {
+ return IsSpecificPrimitiveArray<kVerifyFlags, Primitive::kPrimShort>();
+}
+
+template<VerifyObjectFlags kVerifyFlags>
inline ShortArray* Object::AsShortArray() {
- constexpr auto kNewFlags = RemoveThisFlags(kVerifyFlags);
- DCHECK(GetClass<kVerifyFlags>()->IsArrayClass());
- DCHECK(GetClass<kNewFlags>()->template GetComponentType<kNewFlags>()->IsPrimitiveShort());
+ DCHECK(IsShortArray<kVerifyFlags>());
return down_cast<ShortArray*>(this);
}
template<VerifyObjectFlags kVerifyFlags>
-inline ShortArray* Object::AsShortSizedArray() {
- constexpr auto kNewFlags = RemoveThisFlags(kVerifyFlags);
- DCHECK(GetClass<kVerifyFlags>()->IsArrayClass());
- DCHECK(GetClass<kNewFlags>()->template GetComponentType<kNewFlags>()->IsPrimitiveShort() ||
- GetClass<kNewFlags>()->template GetComponentType<kNewFlags>()->IsPrimitiveChar());
- return down_cast<ShortArray*>(this);
-}
-
-template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption>
inline bool Object::IsIntArray() {
- constexpr auto kNewFlags = RemoveThisFlags(kVerifyFlags);
- ObjPtr<Class> klass = GetClass<kVerifyFlags, kReadBarrierOption>();
- ObjPtr<Class> component_type = klass->GetComponentType<kVerifyFlags, kReadBarrierOption>();
- return component_type != nullptr && component_type->template IsPrimitiveInt<kNewFlags>();
+ return IsSpecificPrimitiveArray<kVerifyFlags, Primitive::kPrimInt>();
}
-template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption>
+template<VerifyObjectFlags kVerifyFlags>
inline IntArray* Object::AsIntArray() {
- DCHECK((IsIntArray<kVerifyFlags, kReadBarrierOption>()));
+ DCHECK((IsIntArray<kVerifyFlags>()));
return down_cast<IntArray*>(this);
}
-template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption>
+template<VerifyObjectFlags kVerifyFlags>
inline bool Object::IsLongArray() {
- constexpr auto kNewFlags = RemoveThisFlags(kVerifyFlags);
- ObjPtr<Class> klass = GetClass<kVerifyFlags, kReadBarrierOption>();
- ObjPtr<Class> component_type = klass->GetComponentType<kVerifyFlags, kReadBarrierOption>();
- return component_type != nullptr && component_type->template IsPrimitiveLong<kNewFlags>();
+ return IsSpecificPrimitiveArray<kVerifyFlags, Primitive::kPrimLong>();
}
-template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption>
+template<VerifyObjectFlags kVerifyFlags>
inline LongArray* Object::AsLongArray() {
- DCHECK((IsLongArray<kVerifyFlags, kReadBarrierOption>()));
+ DCHECK((IsLongArray<kVerifyFlags>()));
return down_cast<LongArray*>(this);
}
template<VerifyObjectFlags kVerifyFlags>
inline bool Object::IsFloatArray() {
- constexpr auto kNewFlags = RemoveThisFlags(kVerifyFlags);
- auto* component_type = GetClass<kVerifyFlags>()->GetComponentType();
- return component_type != nullptr && component_type->template IsPrimitiveFloat<kNewFlags>();
+ return IsSpecificPrimitiveArray<kVerifyFlags, Primitive::kPrimFloat>();
}
template<VerifyObjectFlags kVerifyFlags>
inline FloatArray* Object::AsFloatArray() {
DCHECK(IsFloatArray<kVerifyFlags>());
- constexpr auto kNewFlags = RemoveThisFlags(kVerifyFlags);
- DCHECK(GetClass<kVerifyFlags>()->IsArrayClass());
- DCHECK(GetClass<kNewFlags>()->template GetComponentType<kNewFlags>()->IsPrimitiveFloat());
return down_cast<FloatArray*>(this);
}
template<VerifyObjectFlags kVerifyFlags>
inline bool Object::IsDoubleArray() {
- constexpr auto kNewFlags = RemoveThisFlags(kVerifyFlags);
- auto* component_type = GetClass<kVerifyFlags>()->GetComponentType();
- return component_type != nullptr && component_type->template IsPrimitiveDouble<kNewFlags>();
+ return IsSpecificPrimitiveArray<kVerifyFlags, Primitive::kPrimDouble>();
}
template<VerifyObjectFlags kVerifyFlags>
inline DoubleArray* Object::AsDoubleArray() {
DCHECK(IsDoubleArray<kVerifyFlags>());
- constexpr auto kNewFlags = RemoveThisFlags(kVerifyFlags);
- DCHECK(GetClass<kVerifyFlags>()->IsArrayClass());
- DCHECK(GetClass<kNewFlags>()->template GetComponentType<kNewFlags>()->IsPrimitiveDouble());
return down_cast<DoubleArray*>(this);
}
@@ -351,7 +340,7 @@
// values is OK because of that.
static constexpr ReadBarrierOption kRBO = kWithoutReadBarrier;
size_t result;
- constexpr auto kNewFlags = RemoveThisFlags(kVerifyFlags);
+ constexpr VerifyObjectFlags kNewFlags = RemoveThisFlags(kVerifyFlags);
if (IsArrayInstance<kVerifyFlags>()) {
result = AsArray<kNewFlags>()->template SizeOf<kNewFlags, kRBO>();
} else if (IsClass<kNewFlags>()) {
diff --git a/runtime/mirror/object.h b/runtime/mirror/object.h
index 11e8cca..bca7511 100644
--- a/runtime/mirror/object.h
+++ b/runtime/mirror/object.h
@@ -21,6 +21,7 @@
#include "base/casts.h"
#include "base/enums.h"
#include "base/globals.h"
+#include "dex/primitive.h"
#include "obj_ptr.h"
#include "object_reference.h"
#include "offsets.h"
@@ -199,31 +200,33 @@
Array* AsArray() REQUIRES_SHARED(Locks::mutator_lock_);
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
+ bool IsBooleanArray() REQUIRES_SHARED(Locks::mutator_lock_);
+ template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
BooleanArray* AsBooleanArray() REQUIRES_SHARED(Locks::mutator_lock_);
+
+ template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
+ bool IsByteArray() REQUIRES_SHARED(Locks::mutator_lock_);
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
ByteArray* AsByteArray() REQUIRES_SHARED(Locks::mutator_lock_);
- template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
- ByteArray* AsByteSizedArray() REQUIRES_SHARED(Locks::mutator_lock_);
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
+ bool IsCharArray() REQUIRES_SHARED(Locks::mutator_lock_);
+ template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
CharArray* AsCharArray() REQUIRES_SHARED(Locks::mutator_lock_);
+
+ template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
+ bool IsShortArray() REQUIRES_SHARED(Locks::mutator_lock_);
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
ShortArray* AsShortArray() REQUIRES_SHARED(Locks::mutator_lock_);
- template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
- ShortArray* AsShortSizedArray() REQUIRES_SHARED(Locks::mutator_lock_);
- template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
- ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
+ template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
bool IsIntArray() REQUIRES_SHARED(Locks::mutator_lock_);
- template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
- ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
+ template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
IntArray* AsIntArray() REQUIRES_SHARED(Locks::mutator_lock_);
- template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
- ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
+ template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
bool IsLongArray() REQUIRES_SHARED(Locks::mutator_lock_);
- template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
- ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
+ template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
LongArray* AsLongArray() REQUIRES_SHARED(Locks::mutator_lock_);
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
@@ -757,6 +760,9 @@
size_t num_bytes)
REQUIRES_SHARED(Locks::mutator_lock_);
+ template<VerifyObjectFlags kVerifyFlags, Primitive::Type kType>
+ bool IsSpecificPrimitiveArray() REQUIRES_SHARED(Locks::mutator_lock_);
+
static Atomic<uint32_t> hash_code_seed;
// The Class representing the type of the object.
diff --git a/runtime/native/java_lang_System.cc b/runtime/native/java_lang_System.cc
index 2c4184c..e4bc8ce 100644
--- a/runtime/native/java_lang_System.cc
+++ b/runtime/native/java_lang_System.cc
@@ -101,32 +101,36 @@
case Primitive::kPrimBoolean:
case Primitive::kPrimByte:
DCHECK_EQ(Primitive::ComponentSize(dstComponentPrimitiveType), 1U);
- dstArray->AsByteSizedArray()->Memmove(dstPos, srcArray->AsByteSizedArray(), srcPos, count);
+ // Note: Treating BooleanArray as ByteArray.
+ ObjPtr<mirror::ByteArray>::DownCast(dstArray)->Memmove(
+ dstPos, ObjPtr<mirror::ByteArray>::DownCast(srcArray), srcPos, count);
return;
case Primitive::kPrimChar:
case Primitive::kPrimShort:
DCHECK_EQ(Primitive::ComponentSize(dstComponentPrimitiveType), 2U);
- dstArray->AsShortSizedArray()->Memmove(dstPos, srcArray->AsShortSizedArray(), srcPos, count);
+ // Note: Treating CharArray as ShortArray.
+ ObjPtr<mirror::ShortArray>::DownCast(dstArray)->Memmove(
+ dstPos, ObjPtr<mirror::ShortArray>::DownCast(srcArray), srcPos, count);
return;
case Primitive::kPrimInt:
- DCHECK_EQ(Primitive::ComponentSize(dstComponentPrimitiveType), 4U);
- dstArray->AsIntArray()->Memmove(dstPos, srcArray->AsIntArray(), srcPos, count);
- return;
case Primitive::kPrimFloat:
DCHECK_EQ(Primitive::ComponentSize(dstComponentPrimitiveType), 4U);
- dstArray->AsFloatArray()->Memmove(dstPos, srcArray->AsFloatArray(), srcPos, count);
+ // Note: Treating FloatArray as IntArray.
+ ObjPtr<mirror::IntArray>::DownCast(dstArray)->Memmove(
+ dstPos, ObjPtr<mirror::IntArray>::DownCast(srcArray), srcPos, count);
return;
case Primitive::kPrimLong:
- DCHECK_EQ(Primitive::ComponentSize(dstComponentPrimitiveType), 8U);
- dstArray->AsLongArray()->Memmove(dstPos, srcArray->AsLongArray(), srcPos, count);
- return;
case Primitive::kPrimDouble:
DCHECK_EQ(Primitive::ComponentSize(dstComponentPrimitiveType), 8U);
- dstArray->AsDoubleArray()->Memmove(dstPos, srcArray->AsDoubleArray(), srcPos, count);
+ // Note: Treating DoubleArray as LongArray.
+ ObjPtr<mirror::LongArray>::DownCast(dstArray)->Memmove(
+ dstPos, ObjPtr<mirror::LongArray>::DownCast(srcArray), srcPos, count);
return;
case Primitive::kPrimNot: {
- mirror::ObjectArray<mirror::Object>* dstObjArray = dstArray->AsObjectArray<mirror::Object>();
- mirror::ObjectArray<mirror::Object>* srcObjArray = srcArray->AsObjectArray<mirror::Object>();
+ mirror::ObjectArray<mirror::Object>* dstObjArray =
+ dstArray->AsObjectArray<mirror::Object>();
+ mirror::ObjectArray<mirror::Object>* srcObjArray =
+ srcArray->AsObjectArray<mirror::Object>();
dstObjArray->AssignableMemmove(dstPos, srcObjArray, srcPos, count);
return;
}
diff --git a/runtime/native/sun_misc_Unsafe.cc b/runtime/native/sun_misc_Unsafe.cc
index a739c2d..5014f34 100644
--- a/runtime/native/sun_misc_Unsafe.cc
+++ b/runtime/native/sun_misc_Unsafe.cc
@@ -366,13 +366,17 @@
ObjPtr<mirror::Object> dst = soa.Decode<mirror::Object>(dstObj);
ObjPtr<mirror::Class> component_type = dst->GetClass()->GetComponentType();
if (component_type->IsPrimitiveByte() || component_type->IsPrimitiveBoolean()) {
- copyToArray(srcAddr, MakeObjPtr(dst->AsByteSizedArray()), dst_offset, sz);
+ // Note: Treating BooleanArray as ByteArray.
+ copyToArray(srcAddr, ObjPtr<mirror::ByteArray>::DownCast(dst), dst_offset, sz);
} else if (component_type->IsPrimitiveShort() || component_type->IsPrimitiveChar()) {
- copyToArray(srcAddr, MakeObjPtr(dst->AsShortSizedArray()), dst_offset, sz);
+ // Note: Treating CharArray as ShortArray.
+ copyToArray(srcAddr, ObjPtr<mirror::ShortArray>::DownCast(dst), dst_offset, sz);
} else if (component_type->IsPrimitiveInt() || component_type->IsPrimitiveFloat()) {
- copyToArray(srcAddr, MakeObjPtr(dst->AsIntArray()), dst_offset, sz);
+ // Note: Treating FloatArray as IntArray.
+ copyToArray(srcAddr, ObjPtr<mirror::IntArray>::DownCast(dst), dst_offset, sz);
} else if (component_type->IsPrimitiveLong() || component_type->IsPrimitiveDouble()) {
- copyToArray(srcAddr, MakeObjPtr(dst->AsLongArray()), dst_offset, sz);
+ // Note: Treating DoubleArray as LongArray.
+ copyToArray(srcAddr, ObjPtr<mirror::LongArray>::DownCast(dst), dst_offset, sz);
} else {
ThrowIllegalAccessException("not a primitive array");
}
@@ -397,13 +401,17 @@
ObjPtr<mirror::Object> src = soa.Decode<mirror::Object>(srcObj);
ObjPtr<mirror::Class> component_type = src->GetClass()->GetComponentType();
if (component_type->IsPrimitiveByte() || component_type->IsPrimitiveBoolean()) {
- copyFromArray(dstAddr, MakeObjPtr(src->AsByteSizedArray()), src_offset, sz);
+ // Note: Treating BooleanArray as ByteArray.
+ copyFromArray(dstAddr, ObjPtr<mirror::ByteArray>::DownCast(src), src_offset, sz);
} else if (component_type->IsPrimitiveShort() || component_type->IsPrimitiveChar()) {
- copyFromArray(dstAddr, MakeObjPtr(src->AsShortSizedArray()), src_offset, sz);
+ // Note: Treating CharArray as ShortArray.
+ copyFromArray(dstAddr, ObjPtr<mirror::ShortArray>::DownCast(src), src_offset, sz);
} else if (component_type->IsPrimitiveInt() || component_type->IsPrimitiveFloat()) {
- copyFromArray(dstAddr, MakeObjPtr(src->AsIntArray()), src_offset, sz);
+ // Note: Treating FloatArray as IntArray.
+ copyFromArray(dstAddr, ObjPtr<mirror::IntArray>::DownCast(src), src_offset, sz);
} else if (component_type->IsPrimitiveLong() || component_type->IsPrimitiveDouble()) {
- copyFromArray(dstAddr, MakeObjPtr(src->AsLongArray()), src_offset, sz);
+ // Note: Treating DoubleArray as LongArray.
+ copyFromArray(dstAddr, ObjPtr<mirror::LongArray>::DownCast(src), src_offset, sz);
} else {
ThrowIllegalAccessException("not a primitive array");
}
diff --git a/runtime/oat.h b/runtime/oat.h
index b07294a..3d6415e 100644
--- a/runtime/oat.h
+++ b/runtime/oat.h
@@ -35,7 +35,6 @@
static constexpr uint8_t kOatVersion[] = { '1', '6', '3', '\0' };
static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline";
- static constexpr const char* kDex2OatHostKey = "dex2oat-host";
static constexpr const char* kDebuggableKey = "debuggable";
static constexpr const char* kNativeDebuggableKey = "native-debuggable";
static constexpr const char* kCompilerFilter = "compiler-filter";
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index e577266..3dfa0c4 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -786,7 +786,7 @@
// TODO(calin): We use the JIT class as a proxy for JIT compilation and for
// recoding profiles. Maybe we should consider changing the name to be more clear it's
// not only about compiling. b/28295073.
- if (!safe_mode_ && (jit_options_->UseJitCompilation() || jit_options_->GetSaveProfilingInfo())) {
+ if (jit_options_->UseJitCompilation() || jit_options_->GetSaveProfilingInfo()) {
// Try to load compiler pre zygote to reduce PSS. b/27744947
std::string error_msg;
if (!jit::Jit::LoadCompilerLibrary(&error_msg)) {
@@ -2490,7 +2490,7 @@
DCHECK(!jit_options_->UseJitCompilation());
}
- if (safe_mode_ || (!jit_options_->UseJitCompilation() && !jit_options_->GetSaveProfilingInfo())) {
+ if (!jit_options_->UseJitCompilation() && !jit_options_->GetSaveProfilingInfo()) {
return;
}
@@ -2511,7 +2511,16 @@
}
void Runtime::CreateJit() {
+ DCHECK(jit_ == nullptr);
if (jit_code_cache_.get() == nullptr) {
+ if (!IsSafeMode()) {
+ LOG(WARNING) << "Missing code cache, cannot create JIT.";
+ }
+ return;
+ }
+ if (IsSafeMode()) {
+ LOG(INFO) << "Not creating JIT because of SafeMode.";
+ jit_code_cache_.reset();
return;
}
@@ -2520,7 +2529,7 @@
if (jit == nullptr) {
LOG(WARNING) << "Failed to allocate JIT";
// Release JIT code cache resources (several MB of memory).
- jit_code_cache_.reset(nullptr);
+ jit_code_cache_.reset();
}
}
diff --git a/runtime/runtime.h b/runtime/runtime.h
index be5b3c1..ad4d3bb 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -650,6 +650,13 @@
void DeoptimizeBootImage();
bool IsNativeDebuggable() const {
+ CHECK(!is_zygote_ || IsAotCompiler());
+ return is_native_debuggable_;
+ }
+
+ // Note: prefer not to use this method, but the checked version above. The separation exists
+ // as the runtime state may change for a zygote child.
+ bool IsNativeDebuggableZygoteOK() const {
return is_native_debuggable_;
}
@@ -706,6 +713,11 @@
double GetHashTableMinLoadFactor() const;
double GetHashTableMaxLoadFactor() const;
+ bool IsSafeMode() const {
+ CHECK(!is_zygote_);
+ return safe_mode_;
+ }
+
void SetSafeMode(bool mode) {
safe_mode_ = mode;
}
diff --git a/runtime/runtime_callbacks.cc b/runtime/runtime_callbacks.cc
index 758917c..bf74816 100644
--- a/runtime/runtime_callbacks.cc
+++ b/runtime/runtime_callbacks.cc
@@ -151,6 +151,26 @@
Remove(cb, &monitor_callbacks_);
}
+void RuntimeCallbacks::ThreadParkStart(bool is_absolute, int64_t timeout) {
+ for (ParkCallback * cb : park_callbacks_) {
+ cb->ThreadParkStart(is_absolute, timeout);
+ }
+}
+
+void RuntimeCallbacks::ThreadParkFinished(bool timeout) {
+ for (ParkCallback * cb : park_callbacks_) {
+ cb->ThreadParkFinished(timeout);
+ }
+}
+
+void RuntimeCallbacks::AddParkCallback(ParkCallback* cb) {
+ park_callbacks_.push_back(cb);
+}
+
+void RuntimeCallbacks::RemoveParkCallback(ParkCallback* cb) {
+ Remove(cb, &park_callbacks_);
+}
+
void RuntimeCallbacks::RemoveThreadLifecycleCallback(ThreadLifecycleCallback* cb) {
Remove(cb, &thread_callbacks_);
}
diff --git a/runtime/runtime_callbacks.h b/runtime/runtime_callbacks.h
index 9f0410d..4cce15e 100644
--- a/runtime/runtime_callbacks.h
+++ b/runtime/runtime_callbacks.h
@@ -115,6 +115,19 @@
virtual ~MonitorCallback() {}
};
+class ParkCallback {
+ public:
+ // Called on entry to the Unsafe.#park method
+ virtual void ThreadParkStart(bool is_absolute, int64_t millis_timeout)
+ REQUIRES_SHARED(Locks::mutator_lock_) = 0;
+
+ // Called just after the thread has woken up from going to sleep for a park(). This will only be
+ // called for Unsafe.park() calls where the thread did (or at least could have) gone to sleep.
+ virtual void ThreadParkFinished(bool timed_out) REQUIRES_SHARED(Locks::mutator_lock_) = 0;
+
+ virtual ~ParkCallback() {}
+};
+
// A callback to let parts of the runtime note that they are currently relying on a particular
// method remaining in it's current state. Users should not rely on always being called. If multiple
// callbacks are added the runtime will short-circuit when the first one returns 'true'.
@@ -193,6 +206,11 @@
void AddMonitorCallback(MonitorCallback* cb) REQUIRES_SHARED(Locks::mutator_lock_);
void RemoveMonitorCallback(MonitorCallback* cb) REQUIRES_SHARED(Locks::mutator_lock_);
+ void ThreadParkStart(bool is_absolute, int64_t timeout) REQUIRES_SHARED(Locks::mutator_lock_);
+ void ThreadParkFinished(bool timed_out) REQUIRES_SHARED(Locks::mutator_lock_);
+ void AddParkCallback(ParkCallback* cb) REQUIRES_SHARED(Locks::mutator_lock_);
+ void RemoveParkCallback(ParkCallback* cb) REQUIRES_SHARED(Locks::mutator_lock_);
+
// Returns true if some MethodInspectionCallback indicates the method is being inspected/depended
// on by some code.
bool IsMethodBeingInspected(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_);
@@ -243,6 +261,8 @@
GUARDED_BY(Locks::mutator_lock_);
std::vector<MonitorCallback*> monitor_callbacks_
GUARDED_BY(Locks::mutator_lock_);
+ std::vector<ParkCallback*> park_callbacks_
+ GUARDED_BY(Locks::mutator_lock_);
std::vector<MethodInspectionCallback*> method_inspection_callbacks_
GUARDED_BY(Locks::mutator_lock_);
std::vector<DdmCallback*> ddm_callbacks_
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 7a06be9..e9fed76 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -302,8 +302,9 @@
int old_state = tls32_.park_state_.fetch_add(1, std::memory_order_relaxed);
if (old_state == kNoPermit) {
// no permit was available. block thread until later.
- // TODO: Call to signal jvmti here
+ Runtime::Current()->GetRuntimeCallbacks()->ThreadParkStart(is_absolute, time);
int result = 0;
+ bool timed_out = false;
if (!is_absolute && time == 0) {
// Thread.getState() is documented to return waiting for untimed parks.
ScopedThreadSuspension sts(this, ThreadState::kWaiting);
@@ -351,8 +352,10 @@
}
if (result == -1) {
switch (errno) {
- case EAGAIN:
case ETIMEDOUT:
+ timed_out = true;
+ FALLTHROUGH_INTENDED;
+ case EAGAIN:
case EINTR: break; // park() is allowed to spuriously return
default: PLOG(FATAL) << "Failed to park";
}
@@ -360,6 +363,7 @@
// Mark as no longer waiting, and consume permit if there is one.
tls32_.park_state_.store(kNoPermit, std::memory_order_relaxed);
// TODO: Call to signal jvmti here
+ Runtime::Current()->GetRuntimeCallbacks()->ThreadParkFinished(timed_out);
} else {
// the fetch_add has consumed the permit. immediately return.
DCHECK_EQ(old_state, kPermitAvailable);
diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc
index 94faa62..65039bc 100644
--- a/runtime/well_known_classes.cc
+++ b/runtime/well_known_classes.cc
@@ -122,6 +122,7 @@
jfieldID WellKnownClasses::dalvik_system_DexPathList_dexElements;
jfieldID WellKnownClasses::dalvik_system_DexPathList__Element_dexFile;
jfieldID WellKnownClasses::dalvik_system_VMRuntime_nonSdkApiUsageConsumer;
+jfieldID WellKnownClasses::java_lang_Thread_parkBlocker;
jfieldID WellKnownClasses::java_lang_Thread_daemon;
jfieldID WellKnownClasses::java_lang_Thread_group;
jfieldID WellKnownClasses::java_lang_Thread_lock;
@@ -371,6 +372,7 @@
dalvik_system_DexPathList_dexElements = CacheField(env, dalvik_system_DexPathList, false, "dexElements", "[Ldalvik/system/DexPathList$Element;");
dalvik_system_DexPathList__Element_dexFile = CacheField(env, dalvik_system_DexPathList__Element, false, "dexFile", "Ldalvik/system/DexFile;");
dalvik_system_VMRuntime_nonSdkApiUsageConsumer = CacheField(env, dalvik_system_VMRuntime, true, "nonSdkApiUsageConsumer", "Ljava/util/function/Consumer;");
+ java_lang_Thread_parkBlocker = CacheField(env, java_lang_Thread, false, "parkBlocker", "Ljava/lang/Object;");
java_lang_Thread_daemon = CacheField(env, java_lang_Thread, false, "daemon", "Z");
java_lang_Thread_group = CacheField(env, java_lang_Thread, false, "group", "Ljava/lang/ThreadGroup;");
java_lang_Thread_lock = CacheField(env, java_lang_Thread, false, "lock", "Ljava/lang/Object;");
@@ -518,6 +520,7 @@
dalvik_system_DexPathList_dexElements = nullptr;
dalvik_system_DexPathList__Element_dexFile = nullptr;
dalvik_system_VMRuntime_nonSdkApiUsageConsumer = nullptr;
+ java_lang_Thread_parkBlocker = nullptr;
java_lang_Thread_daemon = nullptr;
java_lang_Thread_group = nullptr;
java_lang_Thread_lock = nullptr;
diff --git a/runtime/well_known_classes.h b/runtime/well_known_classes.h
index 8c85228..130747c 100644
--- a/runtime/well_known_classes.h
+++ b/runtime/well_known_classes.h
@@ -131,6 +131,7 @@
static jfieldID dalvik_system_DexPathList_dexElements;
static jfieldID dalvik_system_DexPathList__Element_dexFile;
static jfieldID dalvik_system_VMRuntime_nonSdkApiUsageConsumer;
+ static jfieldID java_lang_Thread_parkBlocker;
static jfieldID java_lang_Thread_daemon;
static jfieldID java_lang_Thread_group;
static jfieldID java_lang_Thread_lock;
diff --git a/test/004-UnsafeTest/src/Main.java b/test/004-UnsafeTest/src/Main.java
index d43d374..9176e89 100644
--- a/test/004-UnsafeTest/src/Main.java
+++ b/test/004-UnsafeTest/src/Main.java
@@ -32,6 +32,20 @@
}
}
+ private static void check(float actual, float expected, String msg) {
+ if (actual != expected) {
+ System.out.println(msg + " : " + actual + " != " + expected);
+ System.exit(1);
+ }
+ }
+
+ private static void check(double actual, double expected, String msg) {
+ if (actual != expected) {
+ System.out.println(msg + " : " + actual + " != " + expected);
+ System.exit(1);
+ }
+ }
+
private static void check(Object actual, Object expected, String msg) {
if (actual != expected) {
System.out.println(msg + " : " + actual + " != " + expected);
@@ -54,6 +68,7 @@
testArrayIndexScale(unsafe);
testGetAndPutAndCAS(unsafe);
testGetAndPutVolatile(unsafe);
+ testCopyMemoryPrimitiveArrays(unsafe);
}
private static void testArrayBaseOffset(Unsafe unsafe) {
@@ -237,6 +252,38 @@
"Unsafe.getObjectVolatile(Object, long)");
}
+ // Regression test for "copyMemory" operations hitting a DCHECK() for float/double arrays.
+ private static void testCopyMemoryPrimitiveArrays(Unsafe unsafe) {
+ int size = 4 * 1024;
+ long memory = unsafeTestMalloc(size);
+
+ int floatSize = 4;
+ float[] inputFloats = new float[size / floatSize];
+ for (int i = 0; i != inputFloats.length; ++i) {
+ inputFloats[i] = ((float)i) + 0.5f;
+ }
+ float[] outputFloats = new float[size / floatSize];
+ unsafe.copyMemoryFromPrimitiveArray(inputFloats, 0, memory, size);
+ unsafe.copyMemoryToPrimitiveArray(memory, outputFloats, 0, size);
+ for (int i = 0; i != inputFloats.length; ++i) {
+ check(inputFloats[i], outputFloats[i], "unsafe.copyMemory/float");
+ }
+
+ int doubleSize = 8;
+ double[] inputDoubles = new double[size / doubleSize];
+ for (int i = 0; i != inputDoubles.length; ++i) {
+ inputDoubles[i] = ((double)i) + 0.5;
+ }
+ double[] outputDoubles = new double[size / doubleSize];
+ unsafe.copyMemoryFromPrimitiveArray(inputDoubles, 0, memory, size);
+ unsafe.copyMemoryToPrimitiveArray(memory, outputDoubles, 0, size);
+ for (int i = 0; i != inputDoubles.length; ++i) {
+ check(inputDoubles[i], outputDoubles[i], "unsafe.copyMemory/double");
+ }
+
+ unsafeTestFree(memory);
+ }
+
private static class TestClass {
public int intVar = 0;
public long longVar = 0;
@@ -251,4 +298,6 @@
private static native int vmArrayBaseOffset(Class<?> clazz);
private static native int vmArrayIndexScale(Class<?> clazz);
+ private static native long unsafeTestMalloc(long size);
+ private static native void unsafeTestFree(long memory);
}
diff --git a/test/004-UnsafeTest/unsafe_test.cc b/test/004-UnsafeTest/unsafe_test.cc
index 18d9ea8..e970aaa 100644
--- a/test/004-UnsafeTest/unsafe_test.cc
+++ b/test/004-UnsafeTest/unsafe_test.cc
@@ -15,6 +15,7 @@
*/
#include "art_method-inl.h"
+#include "base/casts.h"
#include "jni.h"
#include "mirror/array.h"
#include "mirror/class-inl.h"
@@ -37,4 +38,16 @@
return Primitive::ComponentSize(klass->GetComponentType()->GetPrimitiveType());
}
+extern "C" JNIEXPORT jlong JNICALL Java_Main_unsafeTestMalloc(JNIEnv*, jclass, jlong size) {
+ void* memory = malloc(dchecked_integral_cast<size_t>(size));
+ CHECK(memory != nullptr);
+ return reinterpret_cast64<jlong>(memory);
+}
+
+extern "C" JNIEXPORT void JNICALL Java_Main_unsafeTestFree(JNIEnv*, jclass, jlong memory) {
+ void* mem = reinterpret_cast64<void*>(memory);
+ CHECK(mem != nullptr);
+ free(mem);
+}
+
} // namespace art
diff --git a/test/1931-monitor-events/check b/test/1931-monitor-events/check
new file mode 100644
index 0000000..8a7f844
--- /dev/null
+++ b/test/1931-monitor-events/check
@@ -0,0 +1,22 @@
+#!/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.
+
+# Art sends events for park/unpark, and the RI doesn't. Remove it from the expected output.
+if [[ "$TEST_RUNTIME" == "jvm" ]]; then
+ patch -p0 expected.txt < jvm-expected.patch >/dev/null
+fi
+
+./default-check "$@"
diff --git a/test/1931-monitor-events/expected.txt b/test/1931-monitor-events/expected.txt
index 33a9bd3..f368ae2 100644
--- a/test/1931-monitor-events/expected.txt
+++ b/test/1931-monitor-events/expected.txt
@@ -1,6 +1,9 @@
Testing contended locking.
Locker thread 1 for NamedLock[Lock testLock] contended-LOCKING NamedLock[Lock testLock]
Locker thread 1 for NamedLock[Lock testLock] LOCKED NamedLock[Lock testLock]
+Testing park.
+ParkThread start-monitor-wait NamedLock[Parking blocker object] timeout: 1
+ParkThread monitor-waited NamedLock[Parking blocker object] timed_out: true
Testing monitor wait.
Locker thread 2 for NamedLock[Lock testWait] start-monitor-wait NamedLock[Lock testWait] timeout: 0
Locker thread 2 for NamedLock[Lock testWait] monitor-waited NamedLock[Lock testWait] timed_out: false
diff --git a/test/1931-monitor-events/jvm-expected.patch b/test/1931-monitor-events/jvm-expected.patch
new file mode 100644
index 0000000..7595b14
--- /dev/null
+++ b/test/1931-monitor-events/jvm-expected.patch
@@ -0,0 +1,3 @@
+5,6d4
+< ParkThread start-monitor-wait NamedLock[Parking blocker object] timeout: 1
+< ParkThread monitor-waited NamedLock[Parking blocker object] timed_out: true
diff --git a/test/1931-monitor-events/src/art/Test1931.java b/test/1931-monitor-events/src/art/Test1931.java
index ccefede..f549789 100644
--- a/test/1931-monitor-events/src/art/Test1931.java
+++ b/test/1931-monitor-events/src/art/Test1931.java
@@ -23,6 +23,7 @@
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.*;
+import java.util.concurrent.locks.LockSupport;
import java.util.ListIterator;
import java.util.function.Consumer;
import java.util.function.Function;
@@ -67,6 +68,9 @@
System.out.println("Testing contended locking.");
testLock(new Monitors.NamedLock("Lock testLock"));
+ System.out.println("Testing park.");
+ testPark(new Monitors.NamedLock("Parking blocker object"));
+
System.out.println("Testing monitor wait.");
testWait(new Monitors.NamedLock("Lock testWait"));
@@ -88,6 +92,14 @@
testInteruptWait(new Monitors.NamedLock("Lock testInteruptWait"));
}
+ public static void testPark(Object blocker) throws Exception {
+ Thread holder = new Thread(() -> {
+ LockSupport.parkNanos(blocker, 10); // Should round up to one millisecond
+ }, "ParkThread");
+ holder.start();
+ holder.join();
+ }
+
public static void testInteruptWait(final Monitors.NamedLock lk) throws Exception {
final Monitors.LockController controller1 = new Monitors.LockController(lk);
controller1.DoLock();
diff --git a/test/411-checker-hdiv-hrem-pow2/src/RemTest.java b/test/411-checker-hdiv-hrem-pow2/src/RemTest.java
index 72725c1..54d7847 100644
--- a/test/411-checker-hdiv-hrem-pow2/src/RemTest.java
+++ b/test/411-checker-hdiv-hrem-pow2/src/RemTest.java
@@ -92,6 +92,17 @@
/// CHECK: cmp w{{\d+}}, #0x0
/// CHECK: and w{{\d+}}, w{{\d+}}, #0x1
/// CHECK: cneg w{{\d+}}, w{{\d+}}, lt
+ /// CHECK-START-X86_64: java.lang.Integer RemTest.$noinline$IntMod2(int) disassembly (after)
+ /// CHECK: Rem [{{i\d+}},{{i\d+}}]
+ /// CHECK-NOT: imul
+ /// CHECK-NOT: shr
+ /// CHECK-NOT: imul
+ /// CHECK: mov
+ /// CHECK: and
+ /// CHECK: jz/eq
+ /// CHECK: lea
+ /// CHECK: test
+ /// CHECK: cmovl/nge
private static Integer $noinline$IntMod2(int v) {
int r = v % 2;
return r;
@@ -101,6 +112,17 @@
/// CHECK: cmp w{{\d+}}, #0x0
/// CHECK: and w{{\d+}}, w{{\d+}}, #0x1
/// CHECK: cneg w{{\d+}}, w{{\d+}}, lt
+ /// CHECK-START-X86_64: java.lang.Integer RemTest.$noinline$IntModMinus2(int) disassembly (after)
+ /// CHECK: Rem [{{i\d+}},{{i\d+}}]
+ /// CHECK-NOT: imul
+ /// CHECK-NOT: shr
+ /// CHECK-NOT: imul
+ /// CHECK: mov
+ /// CHECK: and
+ /// CHECK: jz/eq
+ /// CHECK: lea
+ /// CHECK: test
+ /// CHECK: cmovl/nge
private static Integer $noinline$IntModMinus2(int v) {
int r = v % -2;
return r;
@@ -111,6 +133,17 @@
/// CHECK: and w{{\d+}}, w{{\d+}}, #0xf
/// CHECK: and w{{\d+}}, w{{\d+}}, #0xf
/// CHECK: csneg w{{\d+}}, w{{\d+}}, mi
+ /// CHECK-START-X86_64: java.lang.Integer RemTest.$noinline$IntMod16(int) disassembly (after)
+ /// CHECK: Rem [{{i\d+}},{{i\d+}}]
+ /// CHECK-NOT: imul
+ /// CHECK-NOT: shr
+ /// CHECK-NOT: imul
+ /// CHECK: mov
+ /// CHECK: and
+ /// CHECK: jz/eq
+ /// CHECK: lea
+ /// CHECK: test
+ /// CHECK: cmovl/nge
private static Integer $noinline$IntMod16(int v) {
int r = v % 16;
return r;
@@ -121,6 +154,17 @@
/// CHECK: and w{{\d+}}, w{{\d+}}, #0xf
/// CHECK: and w{{\d+}}, w{{\d+}}, #0xf
/// CHECK: csneg w{{\d+}}, w{{\d+}}, mi
+ /// CHECK-START-X86_64: java.lang.Integer RemTest.$noinline$IntModMinus16(int) disassembly (after)
+ /// CHECK: Rem [{{i\d+}},{{i\d+}}]
+ /// CHECK-NOT: imul
+ /// CHECK-NOT: shr
+ /// CHECK-NOT: imul
+ /// CHECK: mov
+ /// CHECK: and
+ /// CHECK: jz/eq
+ /// CHECK: lea
+ /// CHECK: test
+ /// CHECK: cmovl/nge
private static Integer $noinline$IntModMinus16(int v) {
int r = v % -16;
return r;
@@ -131,6 +175,17 @@
/// CHECK: and w{{\d+}}, w{{\d+}}, #0x7fffffff
/// CHECK: and w{{\d+}}, w{{\d+}}, #0x7fffffff
/// CHECK: csneg w{{\d+}}, w{{\d+}}, mi
+ /// CHECK-START-X86_64: java.lang.Integer RemTest.$noinline$IntModIntMin(int) disassembly (after)
+ /// CHECK: Rem [{{i\d+}},{{i\d+}}]
+ /// CHECK-NOT: imul
+ /// CHECK-NOT: shr
+ /// CHECK-NOT: imul
+ /// CHECK: mov
+ /// CHECK: and
+ /// CHECK: jz/eq
+ /// CHECK: lea
+ /// CHECK: test
+ /// CHECK: cmovl/nge
private static Integer $noinline$IntModIntMin(int v) {
int r = v % Integer.MIN_VALUE;
return r;
@@ -211,6 +266,18 @@
/// CHECK: cmp x{{\d+}}, #0x0
/// CHECK: and x{{\d+}}, x{{\d+}}, #0x1
/// CHECK: cneg x{{\d+}}, x{{\d+}}, lt
+ /// CHECK-START-X86_64: java.lang.Long RemTest.$noinline$LongMod2(long) disassembly (after)
+ /// CHECK: Rem [{{j\d+}},{{j\d+}}]
+ /// CHECK-NOT: imul
+ /// CHECK-NOT: shrq
+ /// CHECK-NOT: imulq
+ /// CHECK: movq
+ /// CHECK: andq
+ /// CHECK: jz/eq
+ /// CHECK: movq
+ /// CHECK: sarq
+ /// CHECK: shlq
+ /// CHECK: orq
private static Long $noinline$LongMod2(long v) {
long r = v % 2;
return r;
@@ -220,6 +287,18 @@
/// CHECK: cmp x{{\d+}}, #0x0
/// CHECK: and x{{\d+}}, x{{\d+}}, #0x1
/// CHECK: cneg x{{\d+}}, x{{\d+}}, lt
+ /// CHECK-START-X86_64: java.lang.Long RemTest.$noinline$LongModMinus2(long) disassembly (after)
+ /// CHECK: Rem [{{j\d+}},{{j\d+}}]
+ /// CHECK-NOT: imul
+ /// CHECK-NOT: shrq
+ /// CHECK-NOT: imulq
+ /// CHECK: movq
+ /// CHECK: andq
+ /// CHECK: jz/eq
+ /// CHECK: movq
+ /// CHECK: sarq
+ /// CHECK: shlq
+ /// CHECK: orq
private static Long $noinline$LongModMinus2(long v) {
long r = v % -2;
return r;
@@ -230,6 +309,19 @@
/// CHECK: and x{{\d+}}, x{{\d+}}, #0xf
/// CHECK: and x{{\d+}}, x{{\d+}}, #0xf
/// CHECK: csneg x{{\d+}}, x{{\d+}}, mi
+
+ /// CHECK-START-X86_64: java.lang.Long RemTest.$noinline$LongMod16(long) disassembly (after)
+ /// CHECK: Rem [{{j\d+}},{{j\d+}}]
+ /// CHECK-NOT: imul
+ /// CHECK-NOT: shrq
+ /// CHECK-NOT: imulq
+ /// CHECK: movq
+ /// CHECK: andq
+ /// CHECK: jz/eq
+ /// CHECK: movq
+ /// CHECK: sarq
+ /// CHECK: shlq
+ /// CHECK: orq
private static Long $noinline$LongMod16(long v) {
long r = v % 16;
return r;
@@ -240,6 +332,18 @@
/// CHECK: and x{{\d+}}, x{{\d+}}, #0xf
/// CHECK: and x{{\d+}}, x{{\d+}}, #0xf
/// CHECK: csneg x{{\d+}}, x{{\d+}}, mi
+ /// CHECK-START-X86_64: java.lang.Long RemTest.$noinline$LongModMinus16(long) disassembly (after)
+ /// CHECK: Rem [{{j\d+}},{{j\d+}}]
+ /// CHECK-NOT: imul
+ /// CHECK-NOT: shrq
+ /// CHECK-NOT: imulq
+ /// CHECK: movq
+ /// CHECK: andq
+ /// CHECK: jz/eq
+ /// CHECK: movq
+ /// CHECK: sarq
+ /// CHECK: shlq
+ /// CHECK: orq
private static Long $noinline$LongModMinus16(long v) {
long r = v % -16;
return r;
@@ -250,6 +354,18 @@
/// CHECK: and x{{\d+}}, x{{\d+}}, #0x7fffffffffffffff
/// CHECK: and x{{\d+}}, x{{\d+}}, #0x7fffffffffffffff
/// CHECK: csneg x{{\d+}}, x{{\d+}}, mi
+ /// CHECK-START-X86_64: java.lang.Long RemTest.$noinline$LongModLongMin(long) disassembly (after)
+ /// CHECK: Rem [{{j\d+}},{{j\d+}}]
+ /// CHECK-NOT: imul
+ /// CHECK-NOT: shrq
+ /// CHECK-NOT: imulq
+ /// CHECK: movq
+ /// CHECK: andq
+ /// CHECK: jz/eq
+ /// CHECK: movq
+ /// CHECK: sarq
+ /// CHECK: shlq
+ /// CHECK: orq
private static Long $noinline$LongModLongMin(long v) {
long r = v % Long.MIN_VALUE;
return r;
diff --git a/test/911-get-stack-trace/src/art/PrintThread.java b/test/911-get-stack-trace/src/art/PrintThread.java
index d8b3cbc..798db06 100644
--- a/test/911-get-stack-trace/src/art/PrintThread.java
+++ b/test/911-get-stack-trace/src/art/PrintThread.java
@@ -42,7 +42,7 @@
// may not exist depending on the environment.
public final static String IGNORE_THREAD_NAME_REGEX =
"Binder:|RenderThread|hwuiTask|Jit thread pool worker|Instr:|JDWP|Profile Saver|main|" +
- "queued-work-looper|InstrumentationConnectionThread";
+ "queued-work-looper|InstrumentationConnectionThread|intel_svc_streamer_thread";
public final static Matcher IGNORE_THREADS =
Pattern.compile(IGNORE_THREAD_NAME_REGEX).matcher("");
diff --git a/tools/buildbot-build.sh b/tools/buildbot-build.sh
index 3d70087..c1cc2e2 100755
--- a/tools/buildbot-build.sh
+++ b/tools/buildbot-build.sh
@@ -81,6 +81,8 @@
# These targets are needed for the chroot environment.
make_command+=" crash_dump event-log-tags"
fi
+ # Build the Runtime APEX.
+ make_command+=" com.android.runtime"
mode_suffix="-target"
fi
diff --git a/tools/hiddenapi/hiddenapi.cc b/tools/hiddenapi/hiddenapi.cc
index f61b3e8..65a4945 100644
--- a/tools/hiddenapi/hiddenapi.cc
+++ b/tools/hiddenapi/hiddenapi.cc
@@ -813,6 +813,7 @@
// Create a new MapItem entry with new MapList details.
DexFile::MapItem new_item;
new_item.type_ = old_item.type_;
+ new_item.unused_ = 0u; // initialize to ensure dex output is deterministic (b/119308882)
new_item.size_ = old_item.size_;
new_item.offset_ = new_map_offset;
diff --git a/tools/libcore_gcstress_failures.txt b/tools/libcore_gcstress_failures.txt
index fff1c70..eec45fa 100644
--- a/tools/libcore_gcstress_failures.txt
+++ b/tools/libcore_gcstress_failures.txt
@@ -27,12 +27,14 @@
description: "Timeouts.",
result: EXEC_FAILED,
modes: [device],
- names: ["libcore.java.lang.StringTest#testFastPathString_wellFormedUtf8Sequence",
+ names: ["jsr166.TimeUnitTest#testConvert",
+ "libcore.java.lang.StringTest#testFastPathString_wellFormedUtf8Sequence",
+ "libcore.java.text.DecimalFormatTest#testCurrencySymbolSpacing",
+ "libcore.java.text.SimpleDateFormatTest#testLocales",
"org.apache.harmony.tests.java.lang.ref.ReferenceQueueTest#test_remove",
"org.apache.harmony.tests.java.text.DateFormatTest#test_getAvailableLocales",
+ "org.apache.harmony.tests.java.lang.String2Test#test_getBytes",
"org.apache.harmony.tests.java.util.TimerTest#testOverdueTaskExecutesImmediately",
- "org.apache.harmony.tests.java.util.WeakHashMapTest#test_keySet_hasNext",
- "libcore.java.text.DecimalFormatTest#testCurrencySymbolSpacing",
- "libcore.java.text.SimpleDateFormatTest#testLocales"]
+ "org.apache.harmony.tests.java.util.WeakHashMapTest#test_keySet_hasNext"]
}
]