Merge "X86: Fix LoadString/Class for non-PIC boot image."
diff --git a/compiler/intrinsics_list.h b/compiler/intrinsics_list.h
index 63c23cb..c8a0119 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 69cf9a1..1df884e 100644
--- a/compiler/optimizing/intrinsics_arm.cc
+++ b/compiler/optimizing/intrinsics_arm.cc
@@ -2753,6 +2753,27 @@
}
}
+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 65a8222..b511c5a 100644
--- a/compiler/optimizing/intrinsics_arm64.cc
+++ b/compiler/optimizing/intrinsics_arm64.cc
@@ -3033,6 +3033,28 @@
}
}
+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 356d5bc..2d9781a 100644
--- a/compiler/optimizing/intrinsics_arm_vixl.cc
+++ b/compiler/optimizing/intrinsics_arm_vixl.cc
@@ -3157,6 +3157,29 @@
}
}
+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 eb28742..4731da1 100644
--- a/compiler/optimizing/intrinsics_mips.cc
+++ b/compiler/optimizing/intrinsics_mips.cc
@@ -3257,6 +3257,8 @@
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 a476b2b..00afbcd 100644
--- a/compiler/optimizing/intrinsics_mips64.cc
+++ b/compiler/optimizing/intrinsics_mips64.cc
@@ -2621,6 +2621,8 @@
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 8e45747..57adcc3 100644
--- a/compiler/optimizing/intrinsics_x86.cc
+++ b/compiler/optimizing/intrinsics_x86.cc
@@ -3407,6 +3407,27 @@
}
}
+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 af0b193..773383e 100644
--- a/compiler/optimizing/intrinsics_x86_64.cc
+++ b/compiler/optimizing/intrinsics_x86_64.cc
@@ -3085,6 +3085,27 @@
}
}
+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 f8c4008..eaaf815 100644
--- a/compiler/utils/assembler_thumb_test_expected.cc.inc
+++ b/compiler/utils/assembler_thumb_test_expected.cc.inc
@@ -5535,7 +5535,7 @@
" 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 @@
" 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/arch/context.h b/runtime/arch/context.h
index a500648..d067f66 100644
--- a/runtime/arch/context.h
+++ b/runtime/arch/context.h
@@ -92,7 +92,6 @@
// Switches execution of the executing context to this context
NO_RETURN virtual void DoLongJump() = 0;
- protected:
enum {
kBadGprBase = 0xebad6070,
kBadFprBase = 0xebad8070,
diff --git a/runtime/base/arena_allocator-inl.h b/runtime/base/arena_allocator-inl.h
new file mode 100644
index 0000000..0e43837
--- /dev/null
+++ b/runtime/base/arena_allocator-inl.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_BASE_ARENA_ALLOCATOR_INL_H_
+#define ART_RUNTIME_BASE_ARENA_ALLOCATOR_INL_H_
+
+#include "arena_allocator.h"
+
+namespace art {
+namespace arena_allocator {
+
+static constexpr bool kArenaAllocatorPreciseTracking = kArenaAllocatorCountAllocations;
+
+static constexpr size_t kArenaDefaultSize = kArenaAllocatorPreciseTracking
+ ? 32
+ : 128 * KB;
+
+} // namespace arena_allocator
+} // namespace art
+
+#endif // ART_RUNTIME_BASE_ARENA_ALLOCATOR_INL_H_
diff --git a/runtime/base/arena_allocator.cc b/runtime/base/arena_allocator.cc
index 136ed12..fc5b5b1 100644
--- a/runtime/base/arena_allocator.cc
+++ b/runtime/base/arena_allocator.cc
@@ -19,7 +19,7 @@
#include <iomanip>
#include <numeric>
-#include "arena_allocator.h"
+#include "arena_allocator-inl.h"
#include "logging.h"
#include "mem_map.h"
#include "mutex.h"
@@ -29,7 +29,6 @@
namespace art {
constexpr size_t kMemoryToolRedZoneBytes = 8;
-constexpr size_t Arena::kDefaultSize;
template <bool kCount>
const char* const ArenaAllocatorStatsImpl<kCount>::kAllocNames[] = {
@@ -181,7 +180,7 @@
class MallocArena FINAL : public Arena {
public:
- explicit MallocArena(size_t size = Arena::kDefaultSize);
+ explicit MallocArena(size_t size = arena_allocator::kArenaDefaultSize);
virtual ~MallocArena();
private:
static constexpr size_t RequiredOverallocation() {
@@ -344,6 +343,17 @@
MEMORY_TOOL_MAKE_UNDEFINED(arena->memory_, arena->bytes_allocated_);
}
}
+
+ if (arena_allocator::kArenaAllocatorPreciseTracking) {
+ // Do not reuse arenas when tracking.
+ while (first != nullptr) {
+ Arena* next = first->next_;
+ delete first;
+ first = next;
+ }
+ return;
+ }
+
if (first != nullptr) {
Arena* last = first;
while (last->next_ != nullptr) {
@@ -437,7 +447,7 @@
}
uint8_t* ArenaAllocator::AllocFromNewArena(size_t bytes) {
- Arena* new_arena = pool_->AllocArena(std::max(Arena::kDefaultSize, bytes));
+ Arena* new_arena = pool_->AllocArena(std::max(arena_allocator::kArenaDefaultSize, bytes));
DCHECK(new_arena != nullptr);
DCHECK_LE(bytes, new_arena->Size());
if (static_cast<size_t>(end_ - ptr_) > new_arena->Size() - bytes) {
diff --git a/runtime/base/arena_allocator.h b/runtime/base/arena_allocator.h
index 60b6ea8..5430458 100644
--- a/runtime/base/arena_allocator.h
+++ b/runtime/base/arena_allocator.h
@@ -195,7 +195,6 @@
class Arena {
public:
- static constexpr size_t kDefaultSize = 128 * KB;
Arena();
virtual ~Arena() { }
// Reset is for pre-use and uses memset for performance.
diff --git a/runtime/base/arena_allocator_test.cc b/runtime/base/arena_allocator_test.cc
index fd48a3f..e2c2e2f 100644
--- a/runtime/base/arena_allocator_test.cc
+++ b/runtime/base/arena_allocator_test.cc
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "base/arena_allocator.h"
+#include "base/arena_allocator-inl.h"
#include "base/arena_bit_vector.h"
#include "base/memory_tool.h"
#include "gtest/gtest.h"
@@ -65,23 +65,28 @@
}
TEST_F(ArenaAllocatorTest, LargeAllocations) {
+ if (arena_allocator::kArenaAllocatorPreciseTracking) {
+ printf("WARNING: TEST DISABLED FOR precise arena tracking\n");
+ return;
+ }
+
{
ArenaPool pool;
ArenaAllocator arena(&pool);
// Note: Leaving some space for memory tool red zones.
- void* alloc1 = arena.Alloc(Arena::kDefaultSize * 5 / 8);
- void* alloc2 = arena.Alloc(Arena::kDefaultSize * 2 / 8);
+ void* alloc1 = arena.Alloc(arena_allocator::kArenaDefaultSize * 5 / 8);
+ void* alloc2 = arena.Alloc(arena_allocator::kArenaDefaultSize * 2 / 8);
ASSERT_NE(alloc1, alloc2);
ASSERT_EQ(1u, NumberOfArenas(&arena));
}
{
ArenaPool pool;
ArenaAllocator arena(&pool);
- void* alloc1 = arena.Alloc(Arena::kDefaultSize * 13 / 16);
- void* alloc2 = arena.Alloc(Arena::kDefaultSize * 11 / 16);
+ void* alloc1 = arena.Alloc(arena_allocator::kArenaDefaultSize * 13 / 16);
+ void* alloc2 = arena.Alloc(arena_allocator::kArenaDefaultSize * 11 / 16);
ASSERT_NE(alloc1, alloc2);
ASSERT_EQ(2u, NumberOfArenas(&arena));
- void* alloc3 = arena.Alloc(Arena::kDefaultSize * 7 / 16);
+ void* alloc3 = arena.Alloc(arena_allocator::kArenaDefaultSize * 7 / 16);
ASSERT_NE(alloc1, alloc3);
ASSERT_NE(alloc2, alloc3);
ASSERT_EQ(3u, NumberOfArenas(&arena));
@@ -89,12 +94,12 @@
{
ArenaPool pool;
ArenaAllocator arena(&pool);
- void* alloc1 = arena.Alloc(Arena::kDefaultSize * 13 / 16);
- void* alloc2 = arena.Alloc(Arena::kDefaultSize * 9 / 16);
+ void* alloc1 = arena.Alloc(arena_allocator::kArenaDefaultSize * 13 / 16);
+ void* alloc2 = arena.Alloc(arena_allocator::kArenaDefaultSize * 9 / 16);
ASSERT_NE(alloc1, alloc2);
ASSERT_EQ(2u, NumberOfArenas(&arena));
// Note: Leaving some space for memory tool red zones.
- void* alloc3 = arena.Alloc(Arena::kDefaultSize * 5 / 16);
+ void* alloc3 = arena.Alloc(arena_allocator::kArenaDefaultSize * 5 / 16);
ASSERT_NE(alloc1, alloc3);
ASSERT_NE(alloc2, alloc3);
ASSERT_EQ(2u, NumberOfArenas(&arena));
@@ -102,12 +107,12 @@
{
ArenaPool pool;
ArenaAllocator arena(&pool);
- void* alloc1 = arena.Alloc(Arena::kDefaultSize * 9 / 16);
- void* alloc2 = arena.Alloc(Arena::kDefaultSize * 13 / 16);
+ void* alloc1 = arena.Alloc(arena_allocator::kArenaDefaultSize * 9 / 16);
+ void* alloc2 = arena.Alloc(arena_allocator::kArenaDefaultSize * 13 / 16);
ASSERT_NE(alloc1, alloc2);
ASSERT_EQ(2u, NumberOfArenas(&arena));
// Note: Leaving some space for memory tool red zones.
- void* alloc3 = arena.Alloc(Arena::kDefaultSize * 5 / 16);
+ void* alloc3 = arena.Alloc(arena_allocator::kArenaDefaultSize * 5 / 16);
ASSERT_NE(alloc1, alloc3);
ASSERT_NE(alloc2, alloc3);
ASSERT_EQ(2u, NumberOfArenas(&arena));
@@ -117,9 +122,9 @@
ArenaAllocator arena(&pool);
// Note: Leaving some space for memory tool red zones.
for (size_t i = 0; i != 15; ++i) {
- arena.Alloc(Arena::kDefaultSize * 1 / 16); // Allocate 15 times from the same arena.
+ arena.Alloc(arena_allocator::kArenaDefaultSize * 1 / 16); // Allocate 15 times from the same arena.
ASSERT_EQ(i + 1u, NumberOfArenas(&arena));
- arena.Alloc(Arena::kDefaultSize * 17 / 16); // Allocate a separate arena.
+ arena.Alloc(arena_allocator::kArenaDefaultSize * 17 / 16); // Allocate a separate arena.
ASSERT_EQ(i + 2u, NumberOfArenas(&arena));
}
}
@@ -204,10 +209,11 @@
ArenaPool pool;
ArenaAllocator arena(&pool);
- const size_t original_size = Arena::kDefaultSize - ArenaAllocator::kAlignment * 5;
+ const size_t original_size = arena_allocator::kArenaDefaultSize -
+ ArenaAllocator::kAlignment * 5;
void* original_allocation = arena.Alloc(original_size);
- const size_t new_size = Arena::kDefaultSize + ArenaAllocator::kAlignment * 2;
+ const size_t new_size = arena_allocator::kArenaDefaultSize + ArenaAllocator::kAlignment * 2;
void* realloc_allocation = arena.Realloc(original_allocation, original_size, new_size);
EXPECT_NE(original_allocation, realloc_allocation);
}
@@ -217,12 +223,12 @@
ArenaPool pool;
ArenaAllocator arena(&pool);
- const size_t original_size = Arena::kDefaultSize -
+ const size_t original_size = arena_allocator::kArenaDefaultSize -
ArenaAllocator::kAlignment * 4 -
ArenaAllocator::kAlignment / 2;
void* original_allocation = arena.Alloc(original_size);
- const size_t new_size = Arena::kDefaultSize +
+ const size_t new_size = arena_allocator::kArenaDefaultSize +
ArenaAllocator::kAlignment * 2 +
ArenaAllocator::kAlignment / 2;
void* realloc_allocation = arena.Realloc(original_allocation, original_size, new_size);
@@ -307,11 +313,12 @@
ArenaPool pool;
ArenaAllocator arena(&pool);
- const size_t original_size = Arena::kDefaultSize - ArenaAllocator::kAlignment * 5;
+ const size_t original_size = arena_allocator::kArenaDefaultSize -
+ ArenaAllocator::kAlignment * 5;
void* original_allocation = arena.Alloc(original_size);
ASSERT_TRUE(IsAligned<ArenaAllocator::kAlignment>(original_allocation));
- const size_t new_size = Arena::kDefaultSize + ArenaAllocator::kAlignment * 2;
+ const size_t new_size = arena_allocator::kArenaDefaultSize + ArenaAllocator::kAlignment * 2;
void* realloc_allocation = arena.Realloc(original_allocation, original_size, new_size);
EXPECT_TRUE(IsAligned<ArenaAllocator::kAlignment>(realloc_allocation));
@@ -324,13 +331,13 @@
ArenaPool pool;
ArenaAllocator arena(&pool);
- const size_t original_size = Arena::kDefaultSize -
+ const size_t original_size = arena_allocator::kArenaDefaultSize -
ArenaAllocator::kAlignment * 4 -
ArenaAllocator::kAlignment / 2;
void* original_allocation = arena.Alloc(original_size);
ASSERT_TRUE(IsAligned<ArenaAllocator::kAlignment>(original_allocation));
- const size_t new_size = Arena::kDefaultSize +
+ const size_t new_size = arena_allocator::kArenaDefaultSize +
ArenaAllocator::kAlignment * 2 +
ArenaAllocator::kAlignment / 2;
void* realloc_allocation = arena.Realloc(original_allocation, original_size, new_size);
diff --git a/runtime/base/scoped_arena_allocator.cc b/runtime/base/scoped_arena_allocator.cc
index 7d04fa0..973f9b9 100644
--- a/runtime/base/scoped_arena_allocator.cc
+++ b/runtime/base/scoped_arena_allocator.cc
@@ -16,7 +16,7 @@
#include "scoped_arena_allocator.h"
-#include "arena_allocator.h"
+#include "arena_allocator-inl.h"
#include "base/memory_tool.h"
namespace art {
@@ -54,7 +54,7 @@
uint8_t* ArenaStack::AllocateFromNextArena(size_t rounded_bytes) {
UpdateBytesAllocated();
- size_t allocation_size = std::max(Arena::kDefaultSize, rounded_bytes);
+ size_t allocation_size = std::max(arena_allocator::kArenaDefaultSize, rounded_bytes);
if (UNLIKELY(top_arena_ == nullptr)) {
top_arena_ = bottom_arena_ = stats_and_pool_.pool->AllocArena(allocation_size);
top_arena_->next_ = nullptr;
diff --git a/runtime/generated/asm_support_gen.h b/runtime/generated/asm_support_gen.h
index 06638e7..2de4f19 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_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 b2486a1..489a53b 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 869d430..74e6cd2 100644
--- a/runtime/interpreter/interpreter_intrinsics.cc
+++ b/runtime/interpreter/interpreter_intrinsics.cc
@@ -469,6 +469,7 @@
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/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc
index 56efd25..5232252 100644
--- a/runtime/jit/jit_code_cache.cc
+++ b/runtime/jit/jit_code_cache.cc
@@ -18,6 +18,7 @@
#include <sstream>
+#include "arch/context.h"
#include "art_method-inl.h"
#include "base/enums.h"
#include "base/stl_util.h"
@@ -325,7 +326,8 @@
// Use a sentinel for marking entries in the JIT table that have been cleared.
// This helps diagnosing in case the compiled code tries to wrongly access such
// entries.
-static mirror::Class* const weak_sentinel = reinterpret_cast<mirror::Class*>(0x1);
+static mirror::Class* const weak_sentinel =
+ reinterpret_cast<mirror::Class*>(Context::kBadGprBase + 0xff);
// Helper for the GC to process a weak class in a JIT root table.
static inline void ProcessWeakClass(GcRoot<mirror::Class>* root_ptr,
diff --git a/runtime/monitor.cc b/runtime/monitor.cc
index e365b42..bb33047 100644
--- a/runtime/monitor.cc
+++ b/runtime/monitor.cc
@@ -662,7 +662,7 @@
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 @@
DCHECK(why == kTimedWaiting || why == kSleeping) << why;
self->GetWaitConditionVariable()->TimedWait(self, ms, ns);
}
- was_interrupted = self->IsInterruptedLocked();
+ was_interrupted = self->IsInterrupted();
}
}
@@ -697,10 +697,7 @@
* 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/runtime.cc b/runtime/runtime.cc
index b169373..3697f21 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -390,6 +390,7 @@
low_4gb_arena_pool_.reset();
arena_pool_.reset();
jit_arena_pool_.reset();
+ protected_fault_page_.reset();
MemMap::Shutdown();
// TODO: acquire a static mutex on Runtime to avoid racing.
@@ -1400,6 +1401,27 @@
callbacks_->NextRuntimePhase(RuntimePhaseCallback::RuntimePhase::kInitialAgents);
}
+ // Try to reserve a dedicated fault page. This is allocated for clobbered registers and sentinels.
+ // If we cannot reserve it, log a warning.
+ // Note: This is allocated last so that the heap and other things have priority, if necessary.
+ {
+ constexpr uintptr_t kSentinelAddr =
+ RoundDown(static_cast<uintptr_t>(Context::kBadGprBase), kPageSize);
+ protected_fault_page_.reset(MemMap::MapAnonymous("Sentinel fault page",
+ reinterpret_cast<uint8_t*>(kSentinelAddr),
+ kPageSize,
+ PROT_NONE,
+ true,
+ false,
+ &error_msg));
+ if (protected_fault_page_ == nullptr) {
+ LOG(WARNING) << "Could not reserve sentinel fault page: " << error_msg;
+ } else if (reinterpret_cast<uintptr_t>(protected_fault_page_->Begin()) != kSentinelAddr) {
+ LOG(WARNING) << "Could not reserve sentinel fault page at the right address.";
+ protected_fault_page_.reset();
+ }
+ }
+
VLOG(startup) << "Runtime::Init exiting";
return true;
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 4931382..2e3b8d7 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -81,6 +81,7 @@
class InternTable;
class JavaVMExt;
class LinearAlloc;
+class MemMap;
class MonitorList;
class MonitorPool;
class NullPointerHandler;
@@ -942,6 +943,8 @@
std::atomic<uint32_t> deoptimization_counts_[
static_cast<uint32_t>(DeoptimizationKind::kLast) + 1];
+ std::unique_ptr<MemMap> protected_fault_page_;
+
DISALLOW_COPY_AND_ASSIGN(Runtime);
};
std::ostream& operator<<(std::ostream& os, const Runtime::CalleeSaveType& rhs);
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 653a9bd..6848686 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -1964,7 +1964,6 @@
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 @@
"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 @@
// 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 6abde5b..a60fd58 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -487,15 +487,12 @@
}
// 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 @@
}
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 @@
// 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 @@
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 @@
// 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;
diff --git a/runtime/verifier/reg_type-inl.h b/runtime/verifier/reg_type-inl.h
index aa4a259..9245828 100644
--- a/runtime/verifier/reg_type-inl.h
+++ b/runtime/verifier/reg_type-inl.h
@@ -71,59 +71,62 @@
if (lhs.Equals(rhs)) {
return true;
} else {
- if (lhs.IsBoolean()) {
- return rhs.IsBooleanTypes();
- } else if (lhs.IsByte()) {
- return rhs.IsByteTypes();
- } else if (lhs.IsShort()) {
- return rhs.IsShortTypes();
- } else if (lhs.IsChar()) {
- return rhs.IsCharTypes();
- } else if (lhs.IsInteger()) {
- return rhs.IsIntegralTypes();
- } else if (lhs.IsFloat()) {
- return rhs.IsFloatTypes();
- } else if (lhs.IsLongLo()) {
- return rhs.IsLongTypes();
- } else if (lhs.IsDoubleLo()) {
- return rhs.IsDoubleTypes();
- } else if (lhs.IsConflict()) {
- LOG(WARNING) << "RegType::AssignableFrom lhs is Conflict!";
- return false;
- } else {
- CHECK(lhs.IsReferenceTypes())
- << "Unexpected register type in IsAssignableFrom: '"
- << lhs << "' := '" << rhs << "'";
- if (rhs.IsZero()) {
- return true; // All reference types can be assigned null.
- } else if (!rhs.IsReferenceTypes()) {
- return false; // Expect rhs to be a reference type.
- } else if (lhs.IsUninitializedTypes() || rhs.IsUninitializedTypes()) {
- // Uninitialized types are only allowed to be assigned to themselves.
- // TODO: Once we have a proper "reference" super type, this needs to be extended.
+ switch (lhs.GetAssignmentType()) {
+ case AssignmentType::kBoolean:
+ return rhs.IsBooleanTypes();
+ case AssignmentType::kByte:
+ return rhs.IsByteTypes();
+ case AssignmentType::kShort:
+ return rhs.IsShortTypes();
+ case AssignmentType::kChar:
+ return rhs.IsCharTypes();
+ case AssignmentType::kInteger:
+ return rhs.IsIntegralTypes();
+ case AssignmentType::kFloat:
+ return rhs.IsFloatTypes();
+ case AssignmentType::kLongLo:
+ return rhs.IsLongTypes();
+ case AssignmentType::kDoubleLo:
+ return rhs.IsDoubleTypes();
+ case AssignmentType::kConflict:
+ LOG(WARNING) << "RegType::AssignableFrom lhs is Conflict!";
return false;
- } else if (lhs.IsJavaLangObject()) {
- return true; // All reference types can be assigned to Object.
- } else if (!strict && !lhs.IsUnresolvedTypes() && lhs.GetClass()->IsInterface()) {
- // If we're not strict allow assignment to any interface, see comment in ClassJoin.
- return true;
- } else if (lhs.IsJavaLangObjectArray()) {
- return rhs.IsObjectArrayTypes(); // All reference arrays may be assigned to Object[]
- } else if (lhs.HasClass() && rhs.HasClass()) {
- // Test assignability from the Class point-of-view.
- bool result = lhs.GetClass()->IsAssignableFrom(rhs.GetClass());
- // Record assignability dependency. The `verifier` is null during unit tests and
- // VerifiedMethod::GenerateSafeCastSet.
- if (verifier != nullptr) {
- VerifierDeps::MaybeRecordAssignability(
- verifier->GetDexFile(), lhs.GetClass(), rhs.GetClass(), strict, result);
+ case AssignmentType::kReference:
+ if (rhs.IsZero()) {
+ return true; // All reference types can be assigned null.
+ } else if (!rhs.IsReferenceTypes()) {
+ return false; // Expect rhs to be a reference type.
+ } else if (lhs.IsUninitializedTypes() || rhs.IsUninitializedTypes()) {
+ // Uninitialized types are only allowed to be assigned to themselves.
+ // TODO: Once we have a proper "reference" super type, this needs to be extended.
+ return false;
+ } else if (lhs.IsJavaLangObject()) {
+ return true; // All reference types can be assigned to Object.
+ } else if (!strict && !lhs.IsUnresolvedTypes() && lhs.GetClass()->IsInterface()) {
+ // If we're not strict allow assignment to any interface, see comment in ClassJoin.
+ return true;
+ } else if (lhs.IsJavaLangObjectArray()) {
+ return rhs.IsObjectArrayTypes(); // All reference arrays may be assigned to Object[]
+ } else if (lhs.HasClass() && rhs.HasClass()) {
+ // Test assignability from the Class point-of-view.
+ bool result = lhs.GetClass()->IsAssignableFrom(rhs.GetClass());
+ // Record assignability dependency. The `verifier` is null during unit tests and
+ // VerifiedMethod::GenerateSafeCastSet.
+ if (verifier != nullptr) {
+ VerifierDeps::MaybeRecordAssignability(
+ verifier->GetDexFile(), lhs.GetClass(), rhs.GetClass(), strict, result);
+ }
+ return result;
+ } else {
+ // Unresolved types are only assignable for null and equality.
+ return false;
}
- return result;
- } else {
- // Unresolved types are only assignable for null and equality.
- return false;
- }
+ case AssignmentType::kNotAssignable:
+ break;
}
+ LOG(FATAL) << "Unexpected register type in IsAssignableFrom: '"
+ << lhs << "' := '" << rhs << "'";
+ UNREACHABLE();
}
}
diff --git a/runtime/verifier/reg_type.h b/runtime/verifier/reg_type.h
index dedf77f..25baac5 100644
--- a/runtime/verifier/reg_type.h
+++ b/runtime/verifier/reg_type.h
@@ -268,6 +268,52 @@
static void* operator new(size_t size, ArenaAllocator* arena) = delete;
static void* operator new(size_t size, ScopedArenaAllocator* arena);
+ enum class AssignmentType {
+ kBoolean,
+ kByte,
+ kShort,
+ kChar,
+ kInteger,
+ kFloat,
+ kLongLo,
+ kDoubleLo,
+ kConflict,
+ kReference,
+ kNotAssignable,
+ };
+
+ ALWAYS_INLINE
+ inline AssignmentType GetAssignmentType() const {
+ AssignmentType t = GetAssignmentTypeImpl();
+ if (kIsDebugBuild) {
+ if (IsBoolean()) {
+ CHECK(AssignmentType::kBoolean == t);
+ } else if (IsByte()) {
+ CHECK(AssignmentType::kByte == t);
+ } else if (IsShort()) {
+ CHECK(AssignmentType::kShort == t);
+ } else if (IsChar()) {
+ CHECK(AssignmentType::kChar == t);
+ } else if (IsInteger()) {
+ CHECK(AssignmentType::kInteger == t);
+ } else if (IsFloat()) {
+ CHECK(AssignmentType::kFloat == t);
+ } else if (IsLongLo()) {
+ CHECK(AssignmentType::kLongLo == t);
+ } else if (IsDoubleLo()) {
+ CHECK(AssignmentType::kDoubleLo == t);
+ } else if (IsConflict()) {
+ CHECK(AssignmentType::kConflict == t);
+ } else if (IsReferenceTypes()) {
+ CHECK(AssignmentType::kReference == t);
+ } else {
+ LOG(FATAL) << "Unreachable";
+ UNREACHABLE();
+ }
+ }
+ return t;
+ }
+
protected:
RegType(mirror::Class* klass,
const StringPiece& descriptor,
@@ -285,6 +331,8 @@
}
}
+ virtual AssignmentType GetAssignmentTypeImpl() const = 0;
+
const StringPiece descriptor_;
mutable GcRoot<mirror::Class> klass_; // Non-const only due to moving classes.
const uint16_t cache_id_;
@@ -341,6 +389,10 @@
// Destroy the singleton instance.
static void Destroy();
+ AssignmentType GetAssignmentTypeImpl() const OVERRIDE {
+ return AssignmentType::kConflict;
+ }
+
private:
ConflictType(mirror::Class* klass, const StringPiece& descriptor,
uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_)
@@ -372,6 +424,10 @@
// Destroy the singleton instance.
static void Destroy();
+ AssignmentType GetAssignmentTypeImpl() const OVERRIDE {
+ return AssignmentType::kNotAssignable;
+ }
+
private:
UndefinedType(mirror::Class* klass, const StringPiece& descriptor,
uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_)
@@ -407,6 +463,10 @@
static const IntegerType* GetInstance() PURE;
static void Destroy();
+ AssignmentType GetAssignmentTypeImpl() const OVERRIDE {
+ return AssignmentType::kInteger;
+ }
+
private:
IntegerType(mirror::Class* klass, const StringPiece& descriptor,
uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_)
@@ -427,6 +487,10 @@
static const BooleanType* GetInstance() PURE;
static void Destroy();
+ AssignmentType GetAssignmentTypeImpl() const OVERRIDE {
+ return AssignmentType::kBoolean;
+ }
+
private:
BooleanType(mirror::Class* klass, const StringPiece& descriptor,
uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_)
@@ -448,6 +512,10 @@
static const ByteType* GetInstance() PURE;
static void Destroy();
+ AssignmentType GetAssignmentTypeImpl() const OVERRIDE {
+ return AssignmentType::kByte;
+ }
+
private:
ByteType(mirror::Class* klass, const StringPiece& descriptor,
uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_)
@@ -468,6 +536,10 @@
static const ShortType* GetInstance() PURE;
static void Destroy();
+ AssignmentType GetAssignmentTypeImpl() const OVERRIDE {
+ return AssignmentType::kShort;
+ }
+
private:
ShortType(mirror::Class* klass, const StringPiece& descriptor,
uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_)
@@ -488,6 +560,10 @@
static const CharType* GetInstance() PURE;
static void Destroy();
+ AssignmentType GetAssignmentTypeImpl() const OVERRIDE {
+ return AssignmentType::kChar;
+ }
+
private:
CharType(mirror::Class* klass, const StringPiece& descriptor,
uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_)
@@ -508,6 +584,10 @@
static const FloatType* GetInstance() PURE;
static void Destroy();
+ AssignmentType GetAssignmentTypeImpl() const OVERRIDE {
+ return AssignmentType::kFloat;
+ }
+
private:
FloatType(mirror::Class* klass, const StringPiece& descriptor,
uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_)
@@ -535,6 +615,10 @@
static const LongLoType* GetInstance() PURE;
static void Destroy();
+ AssignmentType GetAssignmentTypeImpl() const OVERRIDE {
+ return AssignmentType::kLongLo;
+ }
+
private:
LongLoType(mirror::Class* klass, const StringPiece& descriptor,
uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_)
@@ -555,6 +639,10 @@
static const LongHiType* GetInstance() PURE;
static void Destroy();
+ AssignmentType GetAssignmentTypeImpl() const OVERRIDE {
+ return AssignmentType::kNotAssignable;
+ }
+
private:
LongHiType(mirror::Class* klass, const StringPiece& descriptor,
uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_)
@@ -576,6 +664,10 @@
static const DoubleLoType* GetInstance() PURE;
static void Destroy();
+ AssignmentType GetAssignmentTypeImpl() const OVERRIDE {
+ return AssignmentType::kDoubleLo;
+ }
+
private:
DoubleLoType(mirror::Class* klass, const StringPiece& descriptor,
uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_)
@@ -596,6 +688,10 @@
static const DoubleHiType* GetInstance() PURE;
static void Destroy();
+ AssignmentType GetAssignmentTypeImpl() const OVERRIDE {
+ return AssignmentType::kNotAssignable;
+ }
+
private:
DoubleHiType(mirror::Class* klass, const StringPiece& descriptor,
uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_)
@@ -658,6 +754,10 @@
}
virtual bool IsConstantTypes() const OVERRIDE { return true; }
+ AssignmentType GetAssignmentTypeImpl() const OVERRIDE {
+ return AssignmentType::kNotAssignable;
+ }
+
private:
const uint32_t constant_;
};
@@ -673,6 +773,10 @@
bool IsPreciseConstant() const OVERRIDE { return true; }
std::string Dump() const OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_);
+
+ AssignmentType GetAssignmentTypeImpl() const OVERRIDE {
+ return AssignmentType::kNotAssignable;
+ }
};
class PreciseConstLoType FINAL : public ConstantType {
@@ -684,6 +788,10 @@
}
bool IsPreciseConstantLo() const OVERRIDE { return true; }
std::string Dump() const OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_);
+
+ AssignmentType GetAssignmentTypeImpl() const OVERRIDE {
+ return AssignmentType::kNotAssignable;
+ }
};
class PreciseConstHiType FINAL : public ConstantType {
@@ -695,6 +803,10 @@
}
bool IsPreciseConstantHi() const OVERRIDE { return true; }
std::string Dump() const OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_);
+
+ AssignmentType GetAssignmentTypeImpl() const OVERRIDE {
+ return AssignmentType::kNotAssignable;
+ }
};
class ImpreciseConstType FINAL : public ConstantType {
@@ -706,6 +818,10 @@
}
bool IsImpreciseConstant() const OVERRIDE { return true; }
std::string Dump() const OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_);
+
+ AssignmentType GetAssignmentTypeImpl() const OVERRIDE {
+ return AssignmentType::kNotAssignable;
+ }
};
class ImpreciseConstLoType FINAL : public ConstantType {
@@ -717,6 +833,10 @@
}
bool IsImpreciseConstantLo() const OVERRIDE { return true; }
std::string Dump() const OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_);
+
+ AssignmentType GetAssignmentTypeImpl() const OVERRIDE {
+ return AssignmentType::kNotAssignable;
+ }
};
class ImpreciseConstHiType FINAL : public ConstantType {
@@ -728,6 +848,10 @@
}
bool IsImpreciseConstantHi() const OVERRIDE { return true; }
std::string Dump() const OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_);
+
+ AssignmentType GetAssignmentTypeImpl() const OVERRIDE {
+ return AssignmentType::kNotAssignable;
+ }
};
// Common parent of all uninitialized types. Uninitialized types are created by
@@ -747,6 +871,10 @@
return allocation_pc_;
}
+ AssignmentType GetAssignmentTypeImpl() const OVERRIDE {
+ return AssignmentType::kReference;
+ }
+
private:
const uint32_t allocation_pc_;
};
@@ -848,6 +976,10 @@
bool HasClassVirtual() const OVERRIDE { return true; }
std::string Dump() const OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_);
+
+ AssignmentType GetAssignmentTypeImpl() const OVERRIDE {
+ return AssignmentType::kReference;
+ }
};
// A type of register holding a reference to an Object of type GetClass and only
@@ -866,6 +998,10 @@
bool HasClassVirtual() const OVERRIDE { return true; }
std::string Dump() const OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_);
+
+ AssignmentType GetAssignmentTypeImpl() const OVERRIDE {
+ return AssignmentType::kReference;
+ }
};
// Common parent of unresolved types.
@@ -876,6 +1012,10 @@
: RegType(nullptr, descriptor, cache_id) {}
bool IsNonZeroReferenceTypes() const OVERRIDE;
+
+ AssignmentType GetAssignmentTypeImpl() const OVERRIDE {
+ return AssignmentType::kReference;
+ }
};
// Similar to ReferenceType except the Class couldn't be loaded. Assignability