diff options
-rw-r--r-- | compiler/intrinsics_list.h | 6 | ||||
-rw-r--r-- | compiler/optimizing/intrinsics_arm.cc | 21 | ||||
-rw-r--r-- | compiler/optimizing/intrinsics_arm64.cc | 22 | ||||
-rw-r--r-- | compiler/optimizing/intrinsics_arm_vixl.cc | 23 | ||||
-rw-r--r-- | compiler/optimizing/intrinsics_mips.cc | 2 | ||||
-rw-r--r-- | compiler/optimizing/intrinsics_mips64.cc | 2 | ||||
-rw-r--r-- | compiler/optimizing/intrinsics_x86.cc | 21 | ||||
-rw-r--r-- | compiler/optimizing/intrinsics_x86_64.cc | 21 | ||||
-rw-r--r-- | compiler/utils/assembler_thumb_test_expected.cc.inc | 4 | ||||
-rw-r--r-- | runtime/generated/asm_support_gen.h | 2 | ||||
-rw-r--r-- | runtime/image.cc | 2 | ||||
-rw-r--r-- | runtime/interpreter/interpreter_intrinsics.cc | 1 | ||||
-rw-r--r-- | runtime/monitor.cc | 9 | ||||
-rw-r--r-- | runtime/thread.cc | 18 | ||||
-rw-r--r-- | runtime/thread.h | 26 |
15 files changed, 150 insertions, 30 deletions
diff --git a/compiler/intrinsics_list.h b/compiler/intrinsics_list.h index 63c23cb074..c8a0119667 100644 --- a/compiler/intrinsics_list.h +++ b/compiler/intrinsics_list.h @@ -28,6 +28,9 @@ // The kNoThrow should be renamed to kNoVisibleThrow, as it is ok to GVN Integer.valueOf // (kNoSideEffects), and it is also OK to remove it if it's unused. +// Note: Thread.interrupted is marked with kAllSideEffects due to the lack of finer grain +// side effects representation. + #define INTRINSICS_LIST(V) \ V(DoubleDoubleToRawLongBits, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Double;", "doubleToRawLongBits", "(D)J") \ V(DoubleDoubleToLongBits, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Double;", "doubleToLongBits", "(D)J") \ @@ -154,7 +157,8 @@ V(UnsafeStoreFence, kVirtual, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "storeFence", "()V") \ V(UnsafeFullFence, kVirtual, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "fullFence", "()V") \ V(ReferenceGetReferent, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Ljava/lang/ref/Reference;", "getReferent", "()Ljava/lang/Object;") \ - V(IntegerValueOf, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Integer;", "valueOf", "(I)Ljava/lang/Integer;") + V(IntegerValueOf, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Integer;", "valueOf", "(I)Ljava/lang/Integer;") \ + V(ThreadInterrupted, kStatic, kNeedsEnvironmentOrCache, kAllSideEffects, kNoThrow, "Ljava/lang/Thread;", "interrupted", "()Z") #endif // ART_COMPILER_INTRINSICS_LIST_H_ #undef ART_COMPILER_INTRINSICS_LIST_H_ // #define is only for lint. diff --git a/compiler/optimizing/intrinsics_arm.cc b/compiler/optimizing/intrinsics_arm.cc index 69cf9a126f..1df884e551 100644 --- a/compiler/optimizing/intrinsics_arm.cc +++ b/compiler/optimizing/intrinsics_arm.cc @@ -2753,6 +2753,27 @@ void IntrinsicCodeGeneratorARM::VisitIntegerValueOf(HInvoke* invoke) { } } +void IntrinsicLocationsBuilderARM::VisitThreadInterrupted(HInvoke* invoke) { + LocationSummary* locations = new (arena_) LocationSummary(invoke, + LocationSummary::kNoCall, + kIntrinsified); + locations->SetOut(Location::RequiresRegister()); +} + +void IntrinsicCodeGeneratorARM::VisitThreadInterrupted(HInvoke* invoke) { + ArmAssembler* assembler = GetAssembler(); + Register out = invoke->GetLocations()->Out().AsRegister<Register>(); + int32_t offset = Thread::InterruptedOffset<kArmPointerSize>().Int32Value(); + __ LoadFromOffset(kLoadWord, out, TR, offset); + Label done; + __ CompareAndBranchIfZero(out, &done); + __ dmb(ISH); + __ LoadImmediate(IP, 0); + __ StoreToOffset(kStoreWord, IP, TR, offset); + __ dmb(ISH); + __ Bind(&done); +} + UNIMPLEMENTED_INTRINSIC(ARM, MathMinDoubleDouble) UNIMPLEMENTED_INTRINSIC(ARM, MathMinFloatFloat) UNIMPLEMENTED_INTRINSIC(ARM, MathMaxDoubleDouble) diff --git a/compiler/optimizing/intrinsics_arm64.cc b/compiler/optimizing/intrinsics_arm64.cc index 65a82229e9..b511c5a18d 100644 --- a/compiler/optimizing/intrinsics_arm64.cc +++ b/compiler/optimizing/intrinsics_arm64.cc @@ -3033,6 +3033,28 @@ void IntrinsicCodeGeneratorARM64::VisitIntegerValueOf(HInvoke* invoke) { } } +void IntrinsicLocationsBuilderARM64::VisitThreadInterrupted(HInvoke* invoke) { + LocationSummary* locations = new (arena_) LocationSummary(invoke, + LocationSummary::kNoCall, + kIntrinsified); + locations->SetOut(Location::RequiresRegister()); +} + +void IntrinsicCodeGeneratorARM64::VisitThreadInterrupted(HInvoke* invoke) { + MacroAssembler* masm = GetVIXLAssembler(); + Register out = RegisterFrom(invoke->GetLocations()->Out(), Primitive::kPrimInt); + UseScratchRegisterScope temps(masm); + Register temp = temps.AcquireX(); + + __ Add(temp, tr, Thread::InterruptedOffset<kArm64PointerSize>().Int32Value()); + __ Ldar(out.W(), MemOperand(temp)); + + vixl::aarch64::Label done; + __ Cbz(out.W(), &done); + __ Stlr(wzr, MemOperand(temp)); + __ Bind(&done); +} + UNIMPLEMENTED_INTRINSIC(ARM64, IntegerHighestOneBit) UNIMPLEMENTED_INTRINSIC(ARM64, LongHighestOneBit) UNIMPLEMENTED_INTRINSIC(ARM64, IntegerLowestOneBit) diff --git a/compiler/optimizing/intrinsics_arm_vixl.cc b/compiler/optimizing/intrinsics_arm_vixl.cc index 356d5bcb0c..2d9781ade8 100644 --- a/compiler/optimizing/intrinsics_arm_vixl.cc +++ b/compiler/optimizing/intrinsics_arm_vixl.cc @@ -3157,6 +3157,29 @@ void IntrinsicCodeGeneratorARMVIXL::VisitIntegerValueOf(HInvoke* invoke) { } } +void IntrinsicLocationsBuilderARMVIXL::VisitThreadInterrupted(HInvoke* invoke) { + LocationSummary* locations = new (arena_) LocationSummary(invoke, + LocationSummary::kNoCall, + kIntrinsified); + locations->SetOut(Location::RequiresRegister()); +} + +void IntrinsicCodeGeneratorARMVIXL::VisitThreadInterrupted(HInvoke* invoke) { + ArmVIXLAssembler* assembler = GetAssembler(); + vixl32::Register out = RegisterFrom(invoke->GetLocations()->Out()); + int32_t offset = Thread::InterruptedOffset<kArmPointerSize>().Int32Value(); + __ Ldr(out, MemOperand(tr, offset)); + UseScratchRegisterScope temps(assembler->GetVIXLAssembler()); + vixl32::Register temp = temps.Acquire(); + vixl32::Label done; + __ CompareAndBranchIfZero(out, &done, /* far_target */ false); + __ Dmb(vixl32::ISH); + __ Mov(temp, 0); + assembler->StoreToOffset(kStoreWord, temp, tr, offset); + __ Dmb(vixl32::ISH); + __ Bind(&done); +} + UNIMPLEMENTED_INTRINSIC(ARMVIXL, MathRoundDouble) // Could be done by changing rounding mode, maybe? UNIMPLEMENTED_INTRINSIC(ARMVIXL, UnsafeCASLong) // High register pressure. UNIMPLEMENTED_INTRINSIC(ARMVIXL, SystemArrayCopyChar) diff --git a/compiler/optimizing/intrinsics_mips.cc b/compiler/optimizing/intrinsics_mips.cc index abf5b122c8..3077e98511 100644 --- a/compiler/optimizing/intrinsics_mips.cc +++ b/compiler/optimizing/intrinsics_mips.cc @@ -3248,6 +3248,8 @@ UNIMPLEMENTED_INTRINSIC(MIPS, UnsafeGetAndSetInt) UNIMPLEMENTED_INTRINSIC(MIPS, UnsafeGetAndSetLong) UNIMPLEMENTED_INTRINSIC(MIPS, UnsafeGetAndSetObject) +UNIMPLEMENTED_INTRINSIC(MIPS, ThreadInterrupted) + UNREACHABLE_INTRINSICS(MIPS) #undef __ diff --git a/compiler/optimizing/intrinsics_mips64.cc b/compiler/optimizing/intrinsics_mips64.cc index 9dce59b2af..e5ee8455dc 100644 --- a/compiler/optimizing/intrinsics_mips64.cc +++ b/compiler/optimizing/intrinsics_mips64.cc @@ -2664,6 +2664,8 @@ UNIMPLEMENTED_INTRINSIC(MIPS64, UnsafeGetAndSetInt) UNIMPLEMENTED_INTRINSIC(MIPS64, UnsafeGetAndSetLong) UNIMPLEMENTED_INTRINSIC(MIPS64, UnsafeGetAndSetObject) +UNIMPLEMENTED_INTRINSIC(MIPS64, ThreadInterrupted) + UNREACHABLE_INTRINSICS(MIPS64) #undef __ diff --git a/compiler/optimizing/intrinsics_x86.cc b/compiler/optimizing/intrinsics_x86.cc index 8e4574774f..57adcc3c2f 100644 --- a/compiler/optimizing/intrinsics_x86.cc +++ b/compiler/optimizing/intrinsics_x86.cc @@ -3407,6 +3407,27 @@ void IntrinsicCodeGeneratorX86::VisitIntegerValueOf(HInvoke* invoke) { } } +void IntrinsicLocationsBuilderX86::VisitThreadInterrupted(HInvoke* invoke) { + LocationSummary* locations = new (arena_) LocationSummary(invoke, + LocationSummary::kNoCall, + kIntrinsified); + locations->SetOut(Location::RequiresRegister()); +} + +void IntrinsicCodeGeneratorX86::VisitThreadInterrupted(HInvoke* invoke) { + X86Assembler* assembler = GetAssembler(); + Register out = invoke->GetLocations()->Out().AsRegister<Register>(); + Address address = Address::Absolute(Thread::InterruptedOffset<kX86PointerSize>().Int32Value()); + NearLabel done; + __ fs()->movl(out, address); + __ testl(out, out); + __ j(kEqual, &done); + __ fs()->movl(address, Immediate(0)); + codegen_->MemoryFence(); + __ Bind(&done); +} + + UNIMPLEMENTED_INTRINSIC(X86, MathRoundDouble) UNIMPLEMENTED_INTRINSIC(X86, FloatIsInfinite) UNIMPLEMENTED_INTRINSIC(X86, DoubleIsInfinite) diff --git a/compiler/optimizing/intrinsics_x86_64.cc b/compiler/optimizing/intrinsics_x86_64.cc index af0b193b03..773383ef1b 100644 --- a/compiler/optimizing/intrinsics_x86_64.cc +++ b/compiler/optimizing/intrinsics_x86_64.cc @@ -3085,6 +3085,27 @@ void IntrinsicCodeGeneratorX86_64::VisitIntegerValueOf(HInvoke* invoke) { } } +void IntrinsicLocationsBuilderX86_64::VisitThreadInterrupted(HInvoke* invoke) { + LocationSummary* locations = new (arena_) LocationSummary(invoke, + LocationSummary::kNoCall, + kIntrinsified); + locations->SetOut(Location::RequiresRegister()); +} + +void IntrinsicCodeGeneratorX86_64::VisitThreadInterrupted(HInvoke* invoke) { + X86_64Assembler* assembler = GetAssembler(); + CpuRegister out = invoke->GetLocations()->Out().AsRegister<CpuRegister>(); + Address address = Address::Absolute + (Thread::InterruptedOffset<kX86_64PointerSize>().Int32Value(), /* no_rip */ true); + NearLabel done; + __ gs()->movl(out, address); + __ testl(out, out); + __ j(kEqual, &done); + __ gs()->movl(address, Immediate(0)); + codegen_->MemoryFence(); + __ Bind(&done); +} + UNIMPLEMENTED_INTRINSIC(X86_64, FloatIsInfinite) UNIMPLEMENTED_INTRINSIC(X86_64, DoubleIsInfinite) diff --git a/compiler/utils/assembler_thumb_test_expected.cc.inc b/compiler/utils/assembler_thumb_test_expected.cc.inc index f8c4008b45..eaaf81518a 100644 --- a/compiler/utils/assembler_thumb_test_expected.cc.inc +++ b/compiler/utils/assembler_thumb_test_expected.cc.inc @@ -5535,7 +5535,7 @@ const char* const VixlJniHelpersResults[] = { " f0: f1bc 0f00 cmp.w ip, #0\n", " f4: bf18 it ne\n", " f6: f20d 4c01 addwne ip, sp, #1025 ; 0x401\n", - " fa: f8d9 c084 ldr.w ip, [r9, #132] ; 0x84\n", + " fa: f8d9 c08c ldr.w ip, [r9, #140] ; 0x8c\n", " fe: f1bc 0f00 cmp.w ip, #0\n", " 102: d171 bne.n 1e8 <VixlJniHelpers+0x1e8>\n", " 104: f8cd c7ff str.w ip, [sp, #2047] ; 0x7ff\n", @@ -5610,7 +5610,7 @@ const char* const VixlJniHelpersResults[] = { " 214: ecbd 8a10 vpop {s16-s31}\n", " 218: e8bd 8de0 ldmia.w sp!, {r5, r6, r7, r8, sl, fp, pc}\n", " 21c: 4660 mov r0, ip\n", - " 21e: f8d9 c2b8 ldr.w ip, [r9, #696] ; 0x2b8\n", + " 21e: f8d9 c2c0 ldr.w ip, [r9, #704] ; 0x2c0\n", " 222: 47e0 blx ip\n", nullptr }; diff --git a/runtime/generated/asm_support_gen.h b/runtime/generated/asm_support_gen.h index 06638e712c..2de4f19222 100644 --- a/runtime/generated/asm_support_gen.h +++ b/runtime/generated/asm_support_gen.h @@ -40,7 +40,7 @@ DEFINE_CHECK_EQ(static_cast<int32_t>(THREAD_FLAGS_OFFSET), (static_cast<int32_t> DEFINE_CHECK_EQ(static_cast<int32_t>(THREAD_ID_OFFSET), (static_cast<int32_t>(art::Thread:: ThinLockIdOffset<art::kRuntimePointerSize>().Int32Value()))) #define THREAD_IS_GC_MARKING_OFFSET 52 DEFINE_CHECK_EQ(static_cast<int32_t>(THREAD_IS_GC_MARKING_OFFSET), (static_cast<int32_t>(art::Thread:: IsGcMarkingOffset<art::kRuntimePointerSize>().Int32Value()))) -#define THREAD_CARD_TABLE_OFFSET 128 +#define THREAD_CARD_TABLE_OFFSET 136 DEFINE_CHECK_EQ(static_cast<int32_t>(THREAD_CARD_TABLE_OFFSET), (static_cast<int32_t>(art::Thread:: CardTableOffset<art::kRuntimePointerSize>().Int32Value()))) #define CODEITEM_INSNS_OFFSET 16 DEFINE_CHECK_EQ(static_cast<int32_t>(CODEITEM_INSNS_OFFSET), (static_cast<int32_t>(__builtin_offsetof(art::DexFile::CodeItem, insns_)))) diff --git a/runtime/image.cc b/runtime/image.cc index b2486a1209..489a53b35c 100644 --- a/runtime/image.cc +++ b/runtime/image.cc @@ -26,7 +26,7 @@ namespace art { const uint8_t ImageHeader::kImageMagic[] = { 'a', 'r', 't', '\n' }; -const uint8_t ImageHeader::kImageVersion[] = { '0', '4', '3', '\0' }; // hash-based DexCache fields +const uint8_t ImageHeader::kImageVersion[] = { '0', '4', '4', '\0' }; // Thread.interrupted ImageHeader::ImageHeader(uint32_t image_begin, uint32_t image_size, diff --git a/runtime/interpreter/interpreter_intrinsics.cc b/runtime/interpreter/interpreter_intrinsics.cc index 869d43061b..74e6cd297d 100644 --- a/runtime/interpreter/interpreter_intrinsics.cc +++ b/runtime/interpreter/interpreter_intrinsics.cc @@ -469,6 +469,7 @@ bool MterpHandleIntrinsic(ShadowFrame* shadow_frame, UNIMPLEMENTED_CASE(UnsafeFullFence /* ()V */) UNIMPLEMENTED_CASE(ReferenceGetReferent /* ()Ljava/lang/Object; */) UNIMPLEMENTED_CASE(IntegerValueOf /* (I)Ljava/lang/Integer; */) + UNIMPLEMENTED_CASE(ThreadInterrupted /* ()Z */) case Intrinsics::kNone: res = false; break; diff --git a/runtime/monitor.cc b/runtime/monitor.cc index e365b42670..bb33047895 100644 --- a/runtime/monitor.cc +++ b/runtime/monitor.cc @@ -662,7 +662,7 @@ void Monitor::Wait(Thread* self, int64_t ms, int32_t ns, monitor_lock_.Unlock(self); // Handle the case where the thread was interrupted before we called wait(). - if (self->IsInterruptedLocked()) { + if (self->IsInterrupted()) { was_interrupted = true; } else { // Wait for a notification or a timeout to occur. @@ -672,7 +672,7 @@ void Monitor::Wait(Thread* self, int64_t ms, int32_t ns, DCHECK(why == kTimedWaiting || why == kSleeping) << why; self->GetWaitConditionVariable()->TimedWait(self, ms, ns); } - was_interrupted = self->IsInterruptedLocked(); + was_interrupted = self->IsInterrupted(); } } @@ -697,10 +697,7 @@ void Monitor::Wait(Thread* self, int64_t ms, int32_t ns, * The doc sayeth: "The interrupted status of the current thread is * cleared when this exception is thrown." */ - { - MutexLock mu(self, *self->GetWaitMutex()); - self->SetInterruptedLocked(false); - } + self->SetInterrupted(false); self->ThrowNewException("Ljava/lang/InterruptedException;", nullptr); } diff --git a/runtime/thread.cc b/runtime/thread.cc index 653a9bd1d4..6848686e5d 100644 --- a/runtime/thread.cc +++ b/runtime/thread.cc @@ -1964,7 +1964,6 @@ void Thread::Shutdown() { Thread::Thread(bool daemon) : tls32_(daemon), wait_monitor_(nullptr), - interrupted_(false), custom_tls_(nullptr), can_call_into_java_(true) { wait_mutex_ = new Mutex("a thread wait mutex"); @@ -1976,6 +1975,7 @@ Thread::Thread(bool daemon) "art::Thread has a size which is not a multiple of 4."); tls32_.state_and_flags.as_struct.flags = 0; tls32_.state_and_flags.as_struct.state = kNative; + tls32_.interrupted.StoreRelaxed(false); memset(&tlsPtr_.held_mutexes[0], 0, sizeof(tlsPtr_.held_mutexes)); std::fill(tlsPtr_.rosalloc_runs, tlsPtr_.rosalloc_runs + kNumRosAllocThreadLocalSizeBracketsInThread, @@ -2269,24 +2269,26 @@ bool Thread::IsJWeakCleared(jweak obj) const { // Implements java.lang.Thread.interrupted. bool Thread::Interrupted() { - MutexLock mu(Thread::Current(), *wait_mutex_); - bool interrupted = IsInterruptedLocked(); - SetInterruptedLocked(false); + DCHECK_EQ(Thread::Current(), this); + // No other thread can concurrently reset the interrupted flag. + bool interrupted = tls32_.interrupted.LoadSequentiallyConsistent(); + if (interrupted) { + tls32_.interrupted.StoreSequentiallyConsistent(false); + } return interrupted; } // Implements java.lang.Thread.isInterrupted. bool Thread::IsInterrupted() { - MutexLock mu(Thread::Current(), *wait_mutex_); - return IsInterruptedLocked(); + return tls32_.interrupted.LoadSequentiallyConsistent(); } void Thread::Interrupt(Thread* self) { MutexLock mu(self, *wait_mutex_); - if (interrupted_) { + if (tls32_.interrupted.LoadSequentiallyConsistent()) { return; } - interrupted_ = true; + tls32_.interrupted.StoreSequentiallyConsistent(true); NotifyLocked(self); } diff --git a/runtime/thread.h b/runtime/thread.h index 6abde5b450..a60fd58ca0 100644 --- a/runtime/thread.h +++ b/runtime/thread.h @@ -487,15 +487,12 @@ class Thread { } // Implements java.lang.Thread.interrupted. - bool Interrupted() REQUIRES(!*wait_mutex_); + bool Interrupted(); // Implements java.lang.Thread.isInterrupted. - bool IsInterrupted() REQUIRES(!*wait_mutex_); - bool IsInterruptedLocked() REQUIRES(wait_mutex_) { - return interrupted_; - } + bool IsInterrupted(); void Interrupt(Thread* self) REQUIRES(!*wait_mutex_); - void SetInterruptedLocked(bool i) REQUIRES(wait_mutex_) { - interrupted_ = i; + void SetInterrupted(bool i) { + tls32_.interrupted.StoreSequentiallyConsistent(i); } void Notify() REQUIRES(!*wait_mutex_); @@ -580,6 +577,13 @@ class Thread { } template<PointerSize pointer_size> + static ThreadOffset<pointer_size> InterruptedOffset() { + return ThreadOffset<pointer_size>( + OFFSETOF_MEMBER(Thread, tls32_) + + OFFSETOF_MEMBER(tls_32bit_sized_values, interrupted)); + } + + template<PointerSize pointer_size> static ThreadOffset<pointer_size> ThreadFlagsOffset() { return ThreadOffset<pointer_size>( OFFSETOF_MEMBER(Thread, tls32_) + @@ -1432,6 +1436,9 @@ class Thread { // GC roots. bool32_t is_gc_marking; + // Thread "interrupted" status; stays raised until queried or thrown. + Atomic<bool32_t> interrupted; + // True if the thread is allowed to access a weak ref (Reference::GetReferent() and system // weaks) and to potentially mark an object alive/gray. This is used for concurrent reference // processing of the CC collector only. This is thread local so that we can enable/disable weak @@ -1631,7 +1638,7 @@ class Thread { gc::accounting::AtomicStack<mirror::Object>* thread_local_mark_stack; } tlsPtr_; - // Guards the 'interrupted_' and 'wait_monitor_' members. + // Guards the 'wait_monitor_' members. Mutex* wait_mutex_ DEFAULT_MUTEX_ACQUIRED_AFTER; // Condition variable waited upon during a wait. @@ -1639,9 +1646,6 @@ class Thread { // Pointer to the monitor lock we're currently waiting on or null if not waiting. Monitor* wait_monitor_ GUARDED_BY(wait_mutex_); - // Thread "interrupted" status; stays raised until queried or thrown. - bool interrupted_ GUARDED_BY(wait_mutex_); - // Debug disable read barrier count, only is checked for debug builds and only in the runtime. uint8_t debug_disallow_read_barrier_ = 0; |