Merge "Fix ScopedArenaAllocator::Reset() for Create()d allocators."
diff --git a/build/Android.common_build.mk b/build/Android.common_build.mk
index d2d6d23..14edb71 100644
--- a/build/Android.common_build.mk
+++ b/build/Android.common_build.mk
@@ -196,7 +196,7 @@
-fno-vectorize
art_debug_cflags := \
- -O1 \
+ -O2 \
-DDYNAMIC_ANNOTATIONS_ENABLED=1 \
-UNDEBUG
@@ -236,6 +236,9 @@
# Warn if switch fallthroughs aren't annotated.
art_clang_cflags += -Wimplicit-fallthrough
+# Enable float equality warnings.
+art_clang_cflags += -Wfloat-equal
+
ifeq ($(ART_HOST_CLANG),true)
ART_HOST_CFLAGS += $(art_clang_cflags)
endif
diff --git a/compiler/jni/jni_compiler_test.cc b/compiler/jni/jni_compiler_test.cc
index a21004c..fd7d350 100644
--- a/compiler/jni/jni_compiler_test.cc
+++ b/compiler/jni/jni_compiler_test.cc
@@ -365,12 +365,12 @@
EXPECT_EQ(0, gJava_MyClassNatives_fooDD_calls);
jdouble result = env_->CallNonvirtualDoubleMethod(jobj_, jklass_, jmethod_,
99.0, 10.0);
- EXPECT_EQ(99.0 - 10.0, result);
+ EXPECT_DOUBLE_EQ(99.0 - 10.0, result);
EXPECT_EQ(1, gJava_MyClassNatives_fooDD_calls);
jdouble a = 3.14159265358979323846;
jdouble b = 0.69314718055994530942;
result = env_->CallNonvirtualDoubleMethod(jobj_, jklass_, jmethod_, a, b);
- EXPECT_EQ(a - b, result);
+ EXPECT_DOUBLE_EQ(a - b, result);
EXPECT_EQ(2, gJava_MyClassNatives_fooDD_calls);
gJava_MyClassNatives_fooDD_calls = 0;
@@ -513,13 +513,13 @@
EXPECT_EQ(0, gJava_MyClassNatives_fooSDD_calls);
jdouble result = env_->CallStaticDoubleMethod(jklass_, jmethod_, 99.0, 10.0);
- EXPECT_EQ(99.0 - 10.0, result);
+ EXPECT_DOUBLE_EQ(99.0 - 10.0, result);
EXPECT_EQ(1, gJava_MyClassNatives_fooSDD_calls);
jdouble a = 3.14159265358979323846;
jdouble b = 0.69314718055994530942;
result = env_->CallStaticDoubleMethod(jklass_, jmethod_, a, b);
- EXPECT_EQ(a - b, result);
- EXPECT_EQ(2, gJava_MyClassNatives_fooSDD_calls);
+ EXPECT_DOUBLE_EQ(a - b, result);
+ EXPECT_DOUBLE_EQ(2, gJava_MyClassNatives_fooSDD_calls);
gJava_MyClassNatives_fooSDD_calls = 0;
}
@@ -539,7 +539,7 @@
SetUpForTest(true, "logD", "(D)D", reinterpret_cast<void*>(&Java_MyClassNatives_logD));
jdouble result = env_->CallStaticDoubleMethod(jklass_, jmethod_, 2.0);
- EXPECT_EQ(log(2.0), result);
+ EXPECT_DOUBLE_EQ(log(2.0), result);
}
JNI_TEST(RunStaticLogDoubleMethod)
@@ -553,7 +553,7 @@
SetUpForTest(true, "logF", "(F)F", reinterpret_cast<void*>(&Java_MyClassNatives_logF));
jfloat result = env_->CallStaticFloatMethod(jklass_, jmethod_, 2.0);
- EXPECT_EQ(logf(2.0), result);
+ EXPECT_FLOAT_EQ(logf(2.0), result);
}
JNI_TEST(RunStaticLogFloatMethod)
@@ -1047,11 +1047,11 @@
jfloat result = env_->CallNonvirtualFloatMethod(jobj_, jklass_, jmethod_,
99.0F, 10.0F);
- EXPECT_EQ(99.0F - 10.0F, result);
+ EXPECT_FLOAT_EQ(99.0F - 10.0F, result);
jfloat a = 3.14159F;
jfloat b = 0.69314F;
result = env_->CallNonvirtualFloatMethod(jobj_, jklass_, jmethod_, a, b);
- EXPECT_EQ(a - b, result);
+ EXPECT_FLOAT_EQ(a - b, result);
}
JNI_TEST(CompileAndRunFloatFloatMethod)
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index e1f513d..7be4349 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -90,7 +90,7 @@
va_end(ap);
}
-static void Usage(const char* fmt, ...) {
+[[noreturn]] static void Usage(const char* fmt, ...) {
va_list ap;
va_start(ap, fmt);
UsageErrorV(fmt, ap);
@@ -662,7 +662,7 @@
Message('W', message);
}
- static void Fatal(const std::string& message) {
+ [[noreturn]] static void Fatal(const std::string& message) {
Message('F', message);
exit(1);
}
diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc
index fbb36f3..4ed428c 100644
--- a/patchoat/patchoat.cc
+++ b/patchoat/patchoat.cc
@@ -644,7 +644,7 @@
va_end(ap);
}
-static void Usage(const char *fmt, ...) {
+[[noreturn]] static void Usage(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
UsageErrorV(fmt, ap);
diff --git a/runtime/arch/x86/fault_handler_x86.cc b/runtime/arch/x86/fault_handler_x86.cc
index 6715fd3..9d74ef5 100644
--- a/runtime/arch/x86/fault_handler_x86.cc
+++ b/runtime/arch/x86/fault_handler_x86.cc
@@ -184,6 +184,7 @@
case 0x80: // group 1, byte immediate.
case 0x83:
+ case 0xc6:
modrm = *pc++;
has_modrm = true;
immediate_size = 1;
diff --git a/runtime/base/histogram-inl.h b/runtime/base/histogram-inl.h
index 4c18ce4..b329a31 100644
--- a/runtime/base/histogram-inl.h
+++ b/runtime/base/histogram-inl.h
@@ -195,6 +195,11 @@
DCHECK_LE(std::abs(out_data->perc_.back() - 1.0), 0.001);
}
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wfloat-equal"
+#endif
+
template <class Value>
inline double Histogram<Value>::Percentile(double per, const CumulativeData& data) const {
DCHECK_GT(data.perc_.size(), 0ull);
@@ -235,6 +240,10 @@
return value;
}
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
+
} // namespace art
#endif // ART_RUNTIME_BASE_HISTOGRAM_INL_H_
diff --git a/runtime/base/histogram_test.cc b/runtime/base/histogram_test.cc
index 454f2ab..7aa5f90 100644
--- a/runtime/base/histogram_test.cc
+++ b/runtime/base/histogram_test.cc
@@ -41,14 +41,14 @@
hist->AddValue(static_cast<uint64_t>(50));
}
mean = hist->Mean();
- EXPECT_EQ(mean, 50);
+ EXPECT_DOUBLE_EQ(mean, 50.0);
hist->Reset();
hist->AddValue(9);
hist->AddValue(17);
hist->AddValue(28);
hist->AddValue(28);
mean = hist->Mean();
- EXPECT_EQ(20.5, mean);
+ EXPECT_DOUBLE_EQ(20.5, mean);
}
TEST(Histtest, VarianceTest) {
@@ -60,7 +60,7 @@
hist->AddValue(28);
hist->AddValue(28);
variance = hist->Variance();
- EXPECT_EQ(64.25, variance);
+ EXPECT_DOUBLE_EQ(64.25, variance);
}
TEST(Histtest, Percentile) {
@@ -236,7 +236,7 @@
}
hist->CreateHistogram(&data);
per_995 = hist->Percentile(0.995, data);
- EXPECT_EQ(per_995, 0);
+ EXPECT_DOUBLE_EQ(per_995, 0.0);
hist->Reset();
for (size_t idx = 0; idx < 200; idx++) {
for (uint64_t val = 1ull; val <= 4ull; val++) {
@@ -246,8 +246,8 @@
hist->CreateHistogram(&data);
per_005 = hist->Percentile(0.005, data);
per_995 = hist->Percentile(0.995, data);
- EXPECT_EQ(1, per_005);
- EXPECT_EQ(4, per_995);
+ EXPECT_DOUBLE_EQ(1.0, per_005);
+ EXPECT_DOUBLE_EQ(4.0, per_995);
}
TEST(Histtest, SpikyValues) {
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index e990181..88e6265 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -907,12 +907,12 @@
mirror::ArtField* s6 = mirror::Class::FindStaticField(soa.Self(), statics, "s6", "F");
EXPECT_EQ(s6->GetTypeAsPrimitiveType(), Primitive::kPrimFloat);
- EXPECT_EQ(0.5, s6->GetFloat(statics.Get()));
+ EXPECT_DOUBLE_EQ(0.5, s6->GetFloat(statics.Get()));
s6->SetFloat<false>(statics.Get(), 0.75);
mirror::ArtField* s7 = mirror::Class::FindStaticField(soa.Self(), statics, "s7", "D");
EXPECT_EQ(s7->GetTypeAsPrimitiveType(), Primitive::kPrimDouble);
- EXPECT_EQ(16777217, s7->GetDouble(statics.Get()));
+ EXPECT_DOUBLE_EQ(16777217.0, s7->GetDouble(statics.Get()));
s7->SetDouble<false>(statics.Get(), 16777219);
mirror::ArtField* s8 = mirror::Class::FindStaticField(soa.Self(), statics, "s8",
@@ -930,8 +930,8 @@
EXPECT_EQ(-535, s3->GetShort(statics.Get()));
EXPECT_EQ(2000000001, s4->GetInt(statics.Get()));
EXPECT_EQ(INT64_C(0x34567890abcdef12), s5->GetLong(statics.Get()));
- EXPECT_EQ(0.75, s6->GetFloat(statics.Get()));
- EXPECT_EQ(16777219, s7->GetDouble(statics.Get()));
+ EXPECT_FLOAT_EQ(0.75, s6->GetFloat(statics.Get()));
+ EXPECT_DOUBLE_EQ(16777219.0, s7->GetDouble(statics.Get()));
EXPECT_TRUE(s8->GetObject(statics.Get())->AsString()->Equals("robot"));
}
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index c53f6b2..971ff89 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -4365,11 +4365,7 @@
Thread* self = Thread::Current();
- // To allow the Walk/InspectAll() below to exclusively-lock the
- // mutator lock, temporarily release the shared access to the
- // mutator lock here by transitioning to the suspended state.
Locks::mutator_lock_->AssertSharedHeld(self);
- self->TransitionFromRunnableToSuspended(kSuspended);
// Send a series of heap segment chunks.
HeapChunkContext context((what == HPSG_WHAT_MERGED_OBJECTS), native);
@@ -4383,32 +4379,39 @@
gc::Heap* heap = Runtime::Current()->GetHeap();
for (const auto& space : heap->GetContinuousSpaces()) {
if (space->IsDlMallocSpace()) {
+ ReaderMutexLock mu(self, *Locks::heap_bitmap_lock_);
// dlmalloc's chunk header is 2 * sizeof(size_t), but if the previous chunk is in use for an
// allocation then the first sizeof(size_t) may belong to it.
context.SetChunkOverhead(sizeof(size_t));
space->AsDlMallocSpace()->Walk(HeapChunkContext::HeapChunkCallback, &context);
} else if (space->IsRosAllocSpace()) {
context.SetChunkOverhead(0);
- space->AsRosAllocSpace()->Walk(HeapChunkContext::HeapChunkCallback, &context);
+ // Need to acquire the mutator lock before the heap bitmap lock with exclusive access since
+ // RosAlloc's internal logic doesn't know to release and reacquire the heap bitmap lock.
+ self->TransitionFromRunnableToSuspended(kSuspended);
+ ThreadList* tl = Runtime::Current()->GetThreadList();
+ tl->SuspendAll();
+ {
+ ReaderMutexLock mu(self, *Locks::heap_bitmap_lock_);
+ space->AsRosAllocSpace()->Walk(HeapChunkContext::HeapChunkCallback, &context);
+ }
+ tl->ResumeAll();
+ self->TransitionFromSuspendedToRunnable();
} else if (space->IsBumpPointerSpace()) {
+ ReaderMutexLock mu(self, *Locks::heap_bitmap_lock_);
context.SetChunkOverhead(0);
- ReaderMutexLock mu(self, *Locks::mutator_lock_);
- WriterMutexLock mu2(self, *Locks::heap_bitmap_lock_);
space->AsBumpPointerSpace()->Walk(BumpPointerSpaceCallback, &context);
} else {
UNIMPLEMENTED(WARNING) << "Not counting objects in space " << *space;
}
context.ResetStartOfNextChunk();
}
+ ReaderMutexLock mu(self, *Locks::heap_bitmap_lock_);
// Walk the large objects, these are not in the AllocSpace.
context.SetChunkOverhead(0);
heap->GetLargeObjectsSpace()->Walk(HeapChunkContext::HeapChunkCallback, &context);
}
- // Shared-lock the mutator lock back.
- self->TransitionFromSuspendedToRunnable();
- Locks::mutator_lock_->AssertSharedHeld(self);
-
// Finally, send a heap end chunk.
Dbg::DdmSendChunk(native ? CHUNK_TYPE("NHEN") : CHUNK_TYPE("HPEN"), sizeof(heap_id), heap_id);
}
diff --git a/runtime/entrypoints/quick/quick_math_entrypoints.cc b/runtime/entrypoints/quick/quick_math_entrypoints.cc
index 014aad3..1c658b7 100644
--- a/runtime/entrypoints/quick/quick_math_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_math_entrypoints.cc
@@ -18,6 +18,11 @@
namespace art {
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wfloat-equal"
+#endif
+
int CmplFloat(float a, float b) {
if (a == b) {
return 0;
@@ -62,6 +67,10 @@
return -1;
}
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
+
extern "C" int64_t artLmul(int64_t a, int64_t b) {
return a * b;
}
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index 054dd46..96903db 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -1275,8 +1275,8 @@
// is at *m = sp. Will update to point to the bottom of the save frame.
//
// Note: assumes ComputeAll() has been run before.
- void LayoutCalleeSaveFrame(StackReference<mirror::ArtMethod>** m, void* sp, HandleScope** table,
- uint32_t* handle_scope_entries)
+ void LayoutCalleeSaveFrame(Thread* self, StackReference<mirror::ArtMethod>** m, void* sp,
+ HandleScope** handle_scope)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
mirror::ArtMethod* method = (*m)->AsMirrorPtr();
@@ -1289,8 +1289,6 @@
sp8 += sizeof(void*); // In the callee-save frame we use a full pointer.
// Under the callee saves put handle scope and new method stack reference.
- *handle_scope_entries = num_handle_scope_references_;
-
size_t handle_scope_size = HandleScope::SizeOf(num_handle_scope_references_);
size_t scope_and_method = handle_scope_size + sizeof(StackReference<mirror::ArtMethod>);
@@ -1300,8 +1298,8 @@
reinterpret_cast<uintptr_t>(sp8), kStackAlignment));
uint8_t* sp8_table = sp8 + sizeof(StackReference<mirror::ArtMethod>);
- *table = reinterpret_cast<HandleScope*>(sp8_table);
- (*table)->SetNumberOfReferences(num_handle_scope_references_);
+ *handle_scope = HandleScope::Create(sp8_table, self->GetTopHandleScope(),
+ num_handle_scope_references_);
// Add a slot for the method pointer, and fill it. Fix the pointer-pointer given to us.
uint8_t* method_pointer = sp8;
@@ -1319,12 +1317,12 @@
// Re-layout the callee-save frame (insert a handle-scope). Then add space for the cookie.
// Returns the new bottom. Note: this may be unaligned.
- uint8_t* LayoutJNISaveFrame(StackReference<mirror::ArtMethod>** m, void* sp, HandleScope** table,
- uint32_t* handle_scope_entries)
+ uint8_t* LayoutJNISaveFrame(Thread* self, StackReference<mirror::ArtMethod>** m, void* sp,
+ HandleScope** handle_scope)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
// First, fix up the layout of the callee-save frame.
// We have to squeeze in the HandleScope, and relocate the method pointer.
- LayoutCalleeSaveFrame(m, sp, table, handle_scope_entries);
+ LayoutCalleeSaveFrame(self, m, sp, handle_scope);
// The bottom of the callee-save frame is now where the method is, *m.
uint8_t* sp8 = reinterpret_cast<uint8_t*>(*m);
@@ -1336,14 +1334,15 @@
}
// WARNING: After this, *sp won't be pointing to the method anymore!
- uint8_t* ComputeLayout(StackReference<mirror::ArtMethod>** m, bool is_static, const char* shorty,
- uint32_t shorty_len, HandleScope** table, uint32_t* handle_scope_entries,
+ uint8_t* ComputeLayout(Thread* self, StackReference<mirror::ArtMethod>** m,
+ bool is_static, const char* shorty, uint32_t shorty_len,
+ HandleScope** handle_scope,
uintptr_t** start_stack, uintptr_t** start_gpr, uint32_t** start_fpr)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
Walk(shorty, shorty_len);
// JNI part.
- uint8_t* sp8 = LayoutJNISaveFrame(m, reinterpret_cast<void*>(*m), table, handle_scope_entries);
+ uint8_t* sp8 = LayoutJNISaveFrame(self, m, reinterpret_cast<void*>(*m), handle_scope);
sp8 = LayoutNativeCall(sp8, start_stack, start_gpr, start_fpr);
@@ -1426,20 +1425,19 @@
// of transitioning into native code.
class BuildGenericJniFrameVisitor FINAL : public QuickArgumentVisitor {
public:
- BuildGenericJniFrameVisitor(StackReference<mirror::ArtMethod>** sp, bool is_static,
- const char* shorty, uint32_t shorty_len, Thread* self)
+ BuildGenericJniFrameVisitor(Thread* self, bool is_static, const char* shorty, uint32_t shorty_len,
+ StackReference<mirror::ArtMethod>** sp)
: QuickArgumentVisitor(*sp, is_static, shorty, shorty_len),
jni_call_(nullptr, nullptr, nullptr, nullptr), sm_(&jni_call_) {
ComputeGenericJniFrameSize fsc;
uintptr_t* start_gpr_reg;
uint32_t* start_fpr_reg;
uintptr_t* start_stack_arg;
- uint32_t handle_scope_entries;
- bottom_of_used_area_ = fsc.ComputeLayout(sp, is_static, shorty, shorty_len, &handle_scope_,
- &handle_scope_entries, &start_stack_arg,
+ bottom_of_used_area_ = fsc.ComputeLayout(self, sp, is_static, shorty, shorty_len,
+ &handle_scope_,
+ &start_stack_arg,
&start_gpr_reg, &start_fpr_reg);
- handle_scope_->SetNumberOfReferences(handle_scope_entries);
jni_call_.Reset(start_gpr_reg, start_fpr_reg, start_stack_arg, handle_scope_);
// jni environment is always first argument
@@ -1611,7 +1609,7 @@
const char* shorty = called->GetShorty(&shorty_len);
// Run the visitor.
- BuildGenericJniFrameVisitor visitor(&sp, called->IsStatic(), shorty, shorty_len, self);
+ BuildGenericJniFrameVisitor visitor(self, called->IsStatic(), shorty, shorty_len, &sp);
visitor.VisitArguments();
visitor.FinalizeHandleScope(self);
diff --git a/runtime/gc/allocator/rosalloc.h b/runtime/gc/allocator/rosalloc.h
index 8374ff7..ad7f901 100644
--- a/runtime/gc/allocator/rosalloc.h
+++ b/runtime/gc/allocator/rosalloc.h
@@ -285,7 +285,7 @@
// Returns the byte size of the bracket size from the index.
static size_t IndexToBracketSize(size_t idx) {
- DCHECK(idx < kNumOfSizeBrackets);
+ DCHECK_LT(idx, kNumOfSizeBrackets);
return bracketSizes[idx];
}
// Returns the index of the size bracket from the bracket size.
diff --git a/runtime/handle_scope-inl.h b/runtime/handle_scope-inl.h
index 7bc811d..2717180 100644
--- a/runtime/handle_scope-inl.h
+++ b/runtime/handle_scope-inl.h
@@ -26,9 +26,10 @@
template<size_t kNumReferences>
inline StackHandleScope<kNumReferences>::StackHandleScope(Thread* self)
- : HandleScope(kNumReferences), self_(self), pos_(0) {
+ : HandleScope(self->GetTopHandleScope(), kNumReferences), self_(self), pos_(0) {
+ COMPILE_ASSERT(kNumReferences >= 1, stack_handle_scope_must_contain_at_least_1_reference);
// TODO: Figure out how to use a compile assert.
- DCHECK_EQ(&references_[0], &references_storage_[0]);
+ CHECK_EQ(&storage_[0], GetReferences());
for (size_t i = 0; i < kNumReferences; ++i) {
SetReference(i, nullptr);
}
diff --git a/runtime/handle_scope.h b/runtime/handle_scope.h
index 99059f9..f795e38 100644
--- a/runtime/handle_scope.h
+++ b/runtime/handle_scope.h
@@ -66,39 +66,28 @@
return link_;
}
- void SetLink(HandleScope* link) {
- DCHECK_NE(this, link);
- link_ = link;
- }
-
- // Sets the number_of_references_ field for constructing tables out of raw memory. Warning: will
- // not resize anything.
- void SetNumberOfReferences(uint32_t num_references) {
- number_of_references_ = num_references;
- }
-
- mirror::Object* GetReference(size_t i) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
- ALWAYS_INLINE {
+ ALWAYS_INLINE mirror::Object* GetReference(size_t i) const
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
DCHECK_LT(i, number_of_references_);
- return references_[i].AsMirrorPtr();
+ return GetReferences()[i].AsMirrorPtr();
}
- Handle<mirror::Object> GetHandle(size_t i) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
- ALWAYS_INLINE {
+ ALWAYS_INLINE Handle<mirror::Object> GetHandle(size_t i)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
DCHECK_LT(i, number_of_references_);
- return Handle<mirror::Object>(&references_[i]);
+ return Handle<mirror::Object>(&GetReferences()[i]);
}
- MutableHandle<mirror::Object> GetMutableHandle(size_t i)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE {
+ ALWAYS_INLINE MutableHandle<mirror::Object> GetMutableHandle(size_t i)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
DCHECK_LT(i, number_of_references_);
- return MutableHandle<mirror::Object>(&references_[i]);
+ return MutableHandle<mirror::Object>(&GetReferences()[i]);
}
- void SetReference(size_t i, mirror::Object* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
- ALWAYS_INLINE {
+ ALWAYS_INLINE void SetReference(size_t i, mirror::Object* object)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
DCHECK_LT(i, number_of_references_);
- references_[i].Assign(object);
+ GetReferences()[i].Assign(object);
}
bool Contains(StackReference<mirror::Object>* handle_scope_entry) const {
@@ -106,39 +95,53 @@
// jni_compiler should have a jobject/jclass as a native method is
// passed in a this pointer or a class
DCHECK_GT(number_of_references_, 0U);
- return &references_[0] <= handle_scope_entry &&
- handle_scope_entry <= &references_[number_of_references_ - 1];
+ return &GetReferences()[0] <= handle_scope_entry &&
+ handle_scope_entry <= &GetReferences()[number_of_references_ - 1];
}
- // Offset of link within HandleScope, used by generated code
+ // Offset of link within HandleScope, used by generated code.
static size_t LinkOffset(size_t pointer_size) {
return 0;
}
- // Offset of length within handle scope, used by generated code
+ // Offset of length within handle scope, used by generated code.
static size_t NumberOfReferencesOffset(size_t pointer_size) {
return pointer_size;
}
- // Offset of link within handle scope, used by generated code
+ // Offset of link within handle scope, used by generated code.
static size_t ReferencesOffset(size_t pointer_size) {
return pointer_size + sizeof(number_of_references_);
}
- protected:
- explicit HandleScope(size_t number_of_references) :
- link_(nullptr), number_of_references_(number_of_references) {
+ // Placement new creation.
+ static HandleScope* Create(void* storage, HandleScope* link, uint32_t num_references)
+ WARN_UNUSED {
+ return new (storage) HandleScope(link, num_references);
}
- HandleScope* link_;
- uint32_t number_of_references_;
+ protected:
+ // Return backing storage used for references.
+ ALWAYS_INLINE StackReference<mirror::Object>* GetReferences() const {
+ uintptr_t address = reinterpret_cast<uintptr_t>(this) + ReferencesOffset(sizeof(void*));
+ return reinterpret_cast<StackReference<mirror::Object>*>(address);
+ }
- // number_of_references_ are available if this is allocated and filled in by jni_compiler.
- StackReference<mirror::Object> references_[0];
+ // Semi-hidden constructor. Construction expected by generated code and StackHandleScope.
+ explicit HandleScope(HandleScope* link, uint32_t num_references) :
+ link_(link), number_of_references_(num_references) {
+ }
+
+ // Link-list of handle scopes. The root is held by a Thread.
+ HandleScope* const link_;
+
+ // Number of handlerized references.
+ const uint32_t number_of_references_;
+
+ // Storage for references.
+ // StackReference<mirror::Object> references_[number_of_references_]
private:
- template<size_t kNumReferences> friend class StackHandleScope;
-
DISALLOW_COPY_AND_ASSIGN(HandleScope);
};
@@ -169,22 +172,22 @@
// Currently unused, using this GetReference instead of the one in HandleScope is preferred to
// avoid compiler optimizations incorrectly optimizing out of bound array accesses.
// TODO: Remove this when it is un-necessary.
- mirror::Object* GetReference(size_t i) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
- ALWAYS_INLINE {
- DCHECK_LT(i, number_of_references_);
- return references_storage_[i].AsMirrorPtr();
+ ALWAYS_INLINE mirror::Object* GetReference(size_t i) const
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ DCHECK_LT(i, kNumReferences);
+ return GetReferences()[i].AsMirrorPtr();
}
- MutableHandle<mirror::Object> GetHandle(size_t i) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
- ALWAYS_INLINE {
- DCHECK_LT(i, number_of_references_);
- return MutableHandle<mirror::Object>(&references_storage_[i]);
+ ALWAYS_INLINE MutableHandle<mirror::Object> GetHandle(size_t i)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ DCHECK_LT(i, kNumReferences);
+ return MutableHandle<mirror::Object>(&GetReferences()[i]);
}
- void SetReference(size_t i, mirror::Object* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
- ALWAYS_INLINE {
- DCHECK_LT(i, number_of_references_);
- references_storage_[i].Assign(object);
+ ALWAYS_INLINE void SetReference(size_t i, mirror::Object* object)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ DCHECK_LT(i, kNumReferences);
+ GetReferences()[i].Assign(object);
}
template<class T>
@@ -204,9 +207,8 @@
}
private:
- // References_storage_ needs to be first so that it appears in the same location as
- // HandleScope::references_.
- StackReference<mirror::Object> references_storage_[kNumReferences];
+ // Reference storage needs to be first as expected by the HandleScope layout.
+ StackReference<mirror::Object> storage_[kNumReferences];
// The thread that the stack handle scope is a linked list upon. The stack handle scope will
// push and pop itself from this thread.
diff --git a/runtime/handle_scope_test.cc b/runtime/handle_scope_test.cc
index 7afd279..dc99987 100644
--- a/runtime/handle_scope_test.cc
+++ b/runtime/handle_scope_test.cc
@@ -25,7 +25,7 @@
template<size_t kNumReferences>
class NoThreadStackHandleScope : public HandleScope {
public:
- explicit NoThreadStackHandleScope() : HandleScope(kNumReferences) {
+ explicit NoThreadStackHandleScope(HandleScope* link) : HandleScope(link, kNumReferences) {
}
~NoThreadStackHandleScope() {
}
@@ -41,10 +41,8 @@
TEST(HandleScopeTest, Offsets) NO_THREAD_SAFETY_ANALYSIS {
// As the members of HandleScope are private, we cannot use OFFSETOF_MEMBER
// here. So do the inverse: set some data, and access it through pointers created from the offsets.
- NoThreadStackHandleScope<1> test_table;
+ NoThreadStackHandleScope<0x9ABC> test_table(reinterpret_cast<HandleScope*>(0x5678));
test_table.SetReference(0, reinterpret_cast<mirror::Object*>(0x1234));
- test_table.SetLink(reinterpret_cast<HandleScope*>(0x5678));
- test_table.SetNumberOfReferences(0x9ABC);
uint8_t* table_base_ptr = reinterpret_cast<uint8_t*>(&test_table);
diff --git a/runtime/interpreter/interpreter_goto_table_impl.cc b/runtime/interpreter/interpreter_goto_table_impl.cc
index db7c452..88d6544 100644
--- a/runtime/interpreter/interpreter_goto_table_impl.cc
+++ b/runtime/interpreter/interpreter_goto_table_impl.cc
@@ -662,6 +662,11 @@
}
HANDLE_INSTRUCTION_END();
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wfloat-equal"
+#endif
+
HANDLE_INSTRUCTION_START(CMPL_FLOAT) {
float val1 = shadow_frame.GetVRegFloat(inst->VRegB_23x());
float val2 = shadow_frame.GetVRegFloat(inst->VRegC_23x());
@@ -726,6 +731,10 @@
}
HANDLE_INSTRUCTION_END();
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
+
HANDLE_INSTRUCTION_START(CMP_LONG) {
int64_t val1 = shadow_frame.GetVRegLong(inst->VRegB_23x());
int64_t val2 = shadow_frame.GetVRegLong(inst->VRegC_23x());
diff --git a/runtime/interpreter/interpreter_switch_impl.cc b/runtime/interpreter/interpreter_switch_impl.cc
index fe0af27..14e8a52 100644
--- a/runtime/interpreter/interpreter_switch_impl.cc
+++ b/runtime/interpreter/interpreter_switch_impl.cc
@@ -562,6 +562,12 @@
inst = inst->RelativeAt(offset);
break;
}
+
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wfloat-equal"
+#endif
+
case Instruction::CMPL_FLOAT: {
PREAMBLE();
float val1 = shadow_frame.GetVRegFloat(inst->VRegB_23x());
@@ -627,6 +633,11 @@
inst = inst->Next_2xx();
break;
}
+
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
+
case Instruction::CMP_LONG: {
PREAMBLE();
int64_t val1 = shadow_frame.GetVRegLong(inst->VRegB_23x());
diff --git a/runtime/jni_internal_test.cc b/runtime/jni_internal_test.cc
index 20d031c..cab907c 100644
--- a/runtime/jni_internal_test.cc
+++ b/runtime/jni_internal_test.cc
@@ -1527,14 +1527,14 @@
EXPECT_TRUE(vm_->SetCheckJniEnabled(old_check_jni));
}
-#define EXPECT_STATIC_PRIMITIVE_FIELD(type, field_name, sig, value1, value2) \
+#define EXPECT_STATIC_PRIMITIVE_FIELD(expect_eq, type, field_name, sig, value1, value2) \
do { \
jfieldID fid = env_->GetStaticFieldID(c, field_name, sig); \
EXPECT_NE(fid, nullptr); \
env_->SetStatic ## type ## Field(c, fid, value1); \
- EXPECT_EQ(value1, env_->GetStatic ## type ## Field(c, fid)); \
+ expect_eq(value1, env_->GetStatic ## type ## Field(c, fid)); \
env_->SetStatic ## type ## Field(c, fid, value2); \
- EXPECT_EQ(value2, env_->GetStatic ## type ## Field(c, fid)); \
+ expect_eq(value2, env_->GetStatic ## type ## Field(c, fid)); \
\
bool old_check_jni = vm_->SetCheckJniEnabled(false); \
{ \
@@ -1560,14 +1560,14 @@
EXPECT_TRUE(vm_->SetCheckJniEnabled(old_check_jni)); \
} while (false)
-#define EXPECT_PRIMITIVE_FIELD(instance, type, field_name, sig, value1, value2) \
+#define EXPECT_PRIMITIVE_FIELD(expect_eq, instance, type, field_name, sig, value1, value2) \
do { \
jfieldID fid = env_->GetFieldID(c, field_name, sig); \
EXPECT_NE(fid, nullptr); \
env_->Set ## type ## Field(instance, fid, value1); \
- EXPECT_EQ(value1, env_->Get ## type ## Field(instance, fid)); \
+ expect_eq(value1, env_->Get ## type ## Field(instance, fid)); \
env_->Set ## type ## Field(instance, fid, value2); \
- EXPECT_EQ(value2, env_->Get ## type ## Field(instance, fid)); \
+ expect_eq(value2, env_->Get ## type ## Field(instance, fid)); \
\
bool old_check_jni = vm_->SetCheckJniEnabled(false); \
CheckJniAbortCatcher jni_abort_catcher; \
@@ -1604,23 +1604,23 @@
jobject o = env_->AllocObject(c);
ASSERT_NE(o, nullptr);
- EXPECT_STATIC_PRIMITIVE_FIELD(Boolean, "sZ", "Z", JNI_TRUE, JNI_FALSE);
- EXPECT_STATIC_PRIMITIVE_FIELD(Byte, "sB", "B", 1, 2);
- EXPECT_STATIC_PRIMITIVE_FIELD(Char, "sC", "C", 'a', 'b');
- EXPECT_STATIC_PRIMITIVE_FIELD(Double, "sD", "D", 1.0, 2.0);
- EXPECT_STATIC_PRIMITIVE_FIELD(Float, "sF", "F", 1.0, 2.0);
- EXPECT_STATIC_PRIMITIVE_FIELD(Int, "sI", "I", 1, 2);
- EXPECT_STATIC_PRIMITIVE_FIELD(Long, "sJ", "J", 1, 2);
- EXPECT_STATIC_PRIMITIVE_FIELD(Short, "sS", "S", 1, 2);
+ EXPECT_STATIC_PRIMITIVE_FIELD(EXPECT_EQ, Boolean, "sZ", "Z", JNI_TRUE, JNI_FALSE);
+ EXPECT_STATIC_PRIMITIVE_FIELD(EXPECT_EQ, Byte, "sB", "B", 1, 2);
+ EXPECT_STATIC_PRIMITIVE_FIELD(EXPECT_EQ, Char, "sC", "C", 'a', 'b');
+ EXPECT_STATIC_PRIMITIVE_FIELD(EXPECT_DOUBLE_EQ, Double, "sD", "D", 1.0, 2.0);
+ EXPECT_STATIC_PRIMITIVE_FIELD(EXPECT_FLOAT_EQ, Float, "sF", "F", 1.0, 2.0);
+ EXPECT_STATIC_PRIMITIVE_FIELD(EXPECT_EQ, Int, "sI", "I", 1, 2);
+ EXPECT_STATIC_PRIMITIVE_FIELD(EXPECT_EQ, Long, "sJ", "J", 1, 2);
+ EXPECT_STATIC_PRIMITIVE_FIELD(EXPECT_EQ, Short, "sS", "S", 1, 2);
- EXPECT_PRIMITIVE_FIELD(o, Boolean, "iZ", "Z", JNI_TRUE, JNI_FALSE);
- EXPECT_PRIMITIVE_FIELD(o, Byte, "iB", "B", 1, 2);
- EXPECT_PRIMITIVE_FIELD(o, Char, "iC", "C", 'a', 'b');
- EXPECT_PRIMITIVE_FIELD(o, Double, "iD", "D", 1.0, 2.0);
- EXPECT_PRIMITIVE_FIELD(o, Float, "iF", "F", 1.0, 2.0);
- EXPECT_PRIMITIVE_FIELD(o, Int, "iI", "I", 1, 2);
- EXPECT_PRIMITIVE_FIELD(o, Long, "iJ", "J", 1, 2);
- EXPECT_PRIMITIVE_FIELD(o, Short, "iS", "S", 1, 2);
+ EXPECT_PRIMITIVE_FIELD(EXPECT_EQ, o, Boolean, "iZ", "Z", JNI_TRUE, JNI_FALSE);
+ EXPECT_PRIMITIVE_FIELD(EXPECT_EQ, o, Byte, "iB", "B", 1, 2);
+ EXPECT_PRIMITIVE_FIELD(EXPECT_EQ, o, Char, "iC", "C", 'a', 'b');
+ EXPECT_PRIMITIVE_FIELD(EXPECT_DOUBLE_EQ, o, Double, "iD", "D", 1.0, 2.0);
+ EXPECT_PRIMITIVE_FIELD(EXPECT_FLOAT_EQ, o, Float, "iF", "F", 1.0, 2.0);
+ EXPECT_PRIMITIVE_FIELD(EXPECT_EQ, o, Int, "iI", "I", 1, 2);
+ EXPECT_PRIMITIVE_FIELD(EXPECT_EQ, o, Long, "iJ", "J", 1, 2);
+ EXPECT_PRIMITIVE_FIELD(EXPECT_EQ, o, Short, "iS", "S", 1, 2);
}
TEST_F(JniInternalTest, GetObjectField_SetObjectField) {
diff --git a/runtime/mirror/object_test.cc b/runtime/mirror/object_test.cc
index 1aeba74..a2a0626 100644
--- a/runtime/mirror/object_test.cc
+++ b/runtime/mirror/object_test.cc
@@ -248,12 +248,6 @@
TEST_F(ObjectTest, PrimitiveArray_Char_Alloc) {
TestPrimitiveArray<CharArray>(class_linker_);
}
-TEST_F(ObjectTest, PrimitiveArray_Double_Alloc) {
- TestPrimitiveArray<DoubleArray>(class_linker_);
-}
-TEST_F(ObjectTest, PrimitiveArray_Float_Alloc) {
- TestPrimitiveArray<FloatArray>(class_linker_);
-}
TEST_F(ObjectTest, PrimitiveArray_Int_Alloc) {
TestPrimitiveArray<IntArray>(class_linker_);
}
@@ -264,6 +258,67 @@
TestPrimitiveArray<ShortArray>(class_linker_);
}
+TEST_F(ObjectTest, PrimitiveArray_Double_Alloc) {
+ typedef DoubleArray ArrayT;
+ ScopedObjectAccess soa(Thread::Current());
+ typedef typename ArrayT::ElementType T;
+
+ ArrayT* a = ArrayT::Alloc(soa.Self(), 2);
+ EXPECT_EQ(2, a->GetLength());
+ EXPECT_DOUBLE_EQ(0, a->Get(0));
+ EXPECT_DOUBLE_EQ(0, a->Get(1));
+ a->Set(0, T(123));
+ EXPECT_DOUBLE_EQ(T(123), a->Get(0));
+ EXPECT_DOUBLE_EQ(0, a->Get(1));
+ a->Set(1, T(321));
+ EXPECT_DOUBLE_EQ(T(123), a->Get(0));
+ EXPECT_DOUBLE_EQ(T(321), a->Get(1));
+
+ Class* aioobe = class_linker_->FindSystemClass(soa.Self(),
+ "Ljava/lang/ArrayIndexOutOfBoundsException;");
+
+ EXPECT_DOUBLE_EQ(0, a->Get(-1));
+ EXPECT_TRUE(soa.Self()->IsExceptionPending());
+ EXPECT_EQ(aioobe, soa.Self()->GetException(NULL)->GetClass());
+ soa.Self()->ClearException();
+
+ EXPECT_DOUBLE_EQ(0, a->Get(2));
+ EXPECT_TRUE(soa.Self()->IsExceptionPending());
+ EXPECT_EQ(aioobe, soa.Self()->GetException(NULL)->GetClass());
+ soa.Self()->ClearException();
+}
+
+TEST_F(ObjectTest, PrimitiveArray_Float_Alloc) {
+ typedef FloatArray ArrayT;
+ ScopedObjectAccess soa(Thread::Current());
+ typedef typename ArrayT::ElementType T;
+
+ ArrayT* a = ArrayT::Alloc(soa.Self(), 2);
+ EXPECT_FLOAT_EQ(2, a->GetLength());
+ EXPECT_FLOAT_EQ(0, a->Get(0));
+ EXPECT_FLOAT_EQ(0, a->Get(1));
+ a->Set(0, T(123));
+ EXPECT_FLOAT_EQ(T(123), a->Get(0));
+ EXPECT_FLOAT_EQ(0, a->Get(1));
+ a->Set(1, T(321));
+ EXPECT_FLOAT_EQ(T(123), a->Get(0));
+ EXPECT_FLOAT_EQ(T(321), a->Get(1));
+
+ Class* aioobe = class_linker_->FindSystemClass(soa.Self(),
+ "Ljava/lang/ArrayIndexOutOfBoundsException;");
+
+ EXPECT_FLOAT_EQ(0, a->Get(-1));
+ EXPECT_TRUE(soa.Self()->IsExceptionPending());
+ EXPECT_EQ(aioobe, soa.Self()->GetException(NULL)->GetClass());
+ soa.Self()->ClearException();
+
+ EXPECT_FLOAT_EQ(0, a->Get(2));
+ EXPECT_TRUE(soa.Self()->IsExceptionPending());
+ EXPECT_EQ(aioobe, soa.Self()->GetException(NULL)->GetClass());
+ soa.Self()->ClearException();
+}
+
+
TEST_F(ObjectTest, CheckAndAllocArrayFromCode) {
// pretend we are trying to call 'new char[3]' from String.toCharArray
ScopedObjectAccess soa(Thread::Current());
diff --git a/runtime/native/java_lang_Runtime.cc b/runtime/native/java_lang_Runtime.cc
index a85eec7..f9a1cee 100644
--- a/runtime/native/java_lang_Runtime.cc
+++ b/runtime/native/java_lang_Runtime.cc
@@ -37,7 +37,7 @@
Runtime::Current()->GetHeap()->CollectGarbage(false);
}
-static void Runtime_nativeExit(JNIEnv*, jclass, jint status) {
+[[noreturn]] static void Runtime_nativeExit(JNIEnv*, jclass, jint status) {
LOG(INFO) << "System.exit called, status: " << status;
Runtime::Current()->CallExitHook(status);
exit(status);
diff --git a/runtime/parsed_options_test.cc b/runtime/parsed_options_test.cc
index 5154d69..61481b1 100644
--- a/runtime/parsed_options_test.cc
+++ b/runtime/parsed_options_test.cc
@@ -64,7 +64,7 @@
EXPECT_EQ(2048U, parsed->heap_initial_size_);
EXPECT_EQ(4 * KB, parsed->heap_maximum_size_);
EXPECT_EQ(1 * MB, parsed->stack_size_);
- EXPECT_EQ(0.75, parsed->heap_target_utilization_);
+ EXPECT_DOUBLE_EQ(0.75, parsed->heap_target_utilization_);
EXPECT_TRUE(test_vfprintf == parsed->hook_vfprintf_);
EXPECT_TRUE(test_exit == parsed->hook_exit_);
EXPECT_TRUE(test_abort == parsed->hook_abort_);
diff --git a/runtime/reflection_test.cc b/runtime/reflection_test.cc
index 75211e0..f8e0f47 100644
--- a/runtime/reflection_test.cc
+++ b/runtime/reflection_test.cc
@@ -193,19 +193,19 @@
args[0].d = 0.0;
JValue result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
- EXPECT_EQ(0.0, result.GetD());
+ EXPECT_DOUBLE_EQ(0.0, result.GetD());
args[0].d = -1.0;
result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
- EXPECT_EQ(-1.0, result.GetD());
+ EXPECT_DOUBLE_EQ(-1.0, result.GetD());
args[0].d = DBL_MAX;
result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
- EXPECT_EQ(DBL_MAX, result.GetD());
+ EXPECT_DOUBLE_EQ(DBL_MAX, result.GetD());
args[0].d = DBL_MIN;
result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
- EXPECT_EQ(DBL_MIN, result.GetD());
+ EXPECT_DOUBLE_EQ(DBL_MIN, result.GetD());
}
void InvokeSumIntIntMethod(bool is_static) {
@@ -375,27 +375,27 @@
args[0].d = 0.0;
args[1].d = 0.0;
JValue result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
- EXPECT_EQ(0.0, result.GetD());
+ EXPECT_DOUBLE_EQ(0.0, result.GetD());
args[0].d = 1.0;
args[1].d = 2.0;
result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
- EXPECT_EQ(3.0, result.GetD());
+ EXPECT_DOUBLE_EQ(3.0, result.GetD());
args[0].d = 1.0;
args[1].d = -2.0;
result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
- EXPECT_EQ(-1.0, result.GetD());
+ EXPECT_DOUBLE_EQ(-1.0, result.GetD());
args[0].d = DBL_MAX;
args[1].d = DBL_MIN;
result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
- EXPECT_EQ(1.7976931348623157e308, result.GetD());
+ EXPECT_DOUBLE_EQ(1.7976931348623157e308, result.GetD());
args[0].d = DBL_MAX;
args[1].d = DBL_MAX;
result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
- EXPECT_EQ(INFINITY, result.GetD());
+ EXPECT_DOUBLE_EQ(INFINITY, result.GetD());
}
void InvokeSumDoubleDoubleDoubleMethod(bool is_static) {
@@ -409,19 +409,19 @@
args[1].d = 0.0;
args[2].d = 0.0;
JValue result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
- EXPECT_EQ(0.0, result.GetD());
+ EXPECT_DOUBLE_EQ(0.0, result.GetD());
args[0].d = 1.0;
args[1].d = 2.0;
args[2].d = 3.0;
result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
- EXPECT_EQ(6.0, result.GetD());
+ EXPECT_DOUBLE_EQ(6.0, result.GetD());
args[0].d = 1.0;
args[1].d = -2.0;
args[2].d = 3.0;
result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
- EXPECT_EQ(2.0, result.GetD());
+ EXPECT_DOUBLE_EQ(2.0, result.GetD());
}
void InvokeSumDoubleDoubleDoubleDoubleMethod(bool is_static) {
@@ -436,21 +436,21 @@
args[2].d = 0.0;
args[3].d = 0.0;
JValue result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
- EXPECT_EQ(0.0, result.GetD());
+ EXPECT_DOUBLE_EQ(0.0, result.GetD());
args[0].d = 1.0;
args[1].d = 2.0;
args[2].d = 3.0;
args[3].d = 4.0;
result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
- EXPECT_EQ(10.0, result.GetD());
+ EXPECT_DOUBLE_EQ(10.0, result.GetD());
args[0].d = 1.0;
args[1].d = -2.0;
args[2].d = 3.0;
args[3].d = -4.0;
result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
- EXPECT_EQ(-2.0, result.GetD());
+ EXPECT_DOUBLE_EQ(-2.0, result.GetD());
}
void InvokeSumDoubleDoubleDoubleDoubleDoubleMethod(bool is_static) {
@@ -466,7 +466,7 @@
args[3].d = 0.0;
args[4].d = 0.0;
JValue result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
- EXPECT_EQ(0.0, result.GetD());
+ EXPECT_DOUBLE_EQ(0.0, result.GetD());
args[0].d = 1.0;
args[1].d = 2.0;
@@ -474,7 +474,7 @@
args[3].d = 4.0;
args[4].d = 5.0;
result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
- EXPECT_EQ(15.0, result.GetD());
+ EXPECT_DOUBLE_EQ(15.0, result.GetD());
args[0].d = 1.0;
args[1].d = -2.0;
@@ -482,7 +482,7 @@
args[3].d = -4.0;
args[4].d = 5.0;
result = InvokeWithJValues(soa, receiver, soa.EncodeMethod(method), args);
- EXPECT_EQ(3.0, result.GetD());
+ EXPECT_DOUBLE_EQ(3.0, result.GetD());
}
JavaVMExt* vm_;
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 1a6c6e0..7bffc33 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -177,10 +177,7 @@
// Aborts semi-cleanly. Used in the implementation of LOG(FATAL), which most
// callers should prefer.
- // This isn't marked ((noreturn)) because then gcc will merge multiple calls
- // in a single function together. This reduces code size slightly, but means
- // that the native stack trace we get may point at the wrong call site.
- static void Abort() LOCKS_EXCLUDED(Locks::abort_lock_);
+ [[noreturn]] static void Abort() LOCKS_EXCLUDED(Locks::abort_lock_);
// Returns the "main" ThreadGroup, used when attaching user threads.
jobject GetMainThreadGroup() const;
diff --git a/runtime/thread.h b/runtime/thread.h
index 998e472..b0be841 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -692,7 +692,7 @@
}
void PushHandleScope(HandleScope* handle_scope) {
- handle_scope->SetLink(tlsPtr_.top_handle_scope);
+ DCHECK_EQ(handle_scope->GetLink(), tlsPtr_.top_handle_scope);
tlsPtr_.top_handle_scope = handle_scope;
}
diff --git a/runtime/transaction_test.cc b/runtime/transaction_test.cc
index a14889c..8c4b90d 100644
--- a/runtime/transaction_test.cc
+++ b/runtime/transaction_test.cc
@@ -147,12 +147,12 @@
mirror::ArtField* floatField = h_klass->FindDeclaredStaticField("floatField", "F");
ASSERT_TRUE(floatField != nullptr);
ASSERT_EQ(floatField->GetTypeAsPrimitiveType(), Primitive::kPrimFloat);
- ASSERT_EQ(floatField->GetFloat(h_klass.Get()), static_cast<float>(0.0f));
+ ASSERT_FLOAT_EQ(floatField->GetFloat(h_klass.Get()), static_cast<float>(0.0f));
mirror::ArtField* doubleField = h_klass->FindDeclaredStaticField("doubleField", "D");
ASSERT_TRUE(doubleField != nullptr);
ASSERT_EQ(doubleField->GetTypeAsPrimitiveType(), Primitive::kPrimDouble);
- ASSERT_EQ(doubleField->GetDouble(h_klass.Get()), static_cast<double>(0.0));
+ ASSERT_DOUBLE_EQ(doubleField->GetDouble(h_klass.Get()), static_cast<double>(0.0));
mirror::ArtField* objectField = h_klass->FindDeclaredStaticField("objectField",
"Ljava/lang/Object;");
@@ -190,8 +190,8 @@
EXPECT_EQ(shortField->GetShort(h_klass.Get()), 0);
EXPECT_EQ(intField->GetInt(h_klass.Get()), 0);
EXPECT_EQ(longField->GetLong(h_klass.Get()), static_cast<int64_t>(0));
- EXPECT_EQ(floatField->GetFloat(h_klass.Get()), static_cast<float>(0.0f));
- EXPECT_EQ(doubleField->GetDouble(h_klass.Get()), static_cast<double>(0.0));
+ EXPECT_FLOAT_EQ(floatField->GetFloat(h_klass.Get()), static_cast<float>(0.0f));
+ EXPECT_DOUBLE_EQ(doubleField->GetDouble(h_klass.Get()), static_cast<double>(0.0));
EXPECT_EQ(objectField->GetObject(h_klass.Get()), nullptr);
}
@@ -246,12 +246,12 @@
mirror::ArtField* floatField = h_klass->FindDeclaredInstanceField("floatField", "F");
ASSERT_TRUE(floatField != nullptr);
ASSERT_EQ(floatField->GetTypeAsPrimitiveType(), Primitive::kPrimFloat);
- ASSERT_EQ(floatField->GetFloat(h_instance.Get()), static_cast<float>(0.0f));
+ ASSERT_FLOAT_EQ(floatField->GetFloat(h_instance.Get()), static_cast<float>(0.0f));
mirror::ArtField* doubleField = h_klass->FindDeclaredInstanceField("doubleField", "D");
ASSERT_TRUE(doubleField != nullptr);
ASSERT_EQ(doubleField->GetTypeAsPrimitiveType(), Primitive::kPrimDouble);
- ASSERT_EQ(doubleField->GetDouble(h_instance.Get()), static_cast<double>(0.0));
+ ASSERT_DOUBLE_EQ(doubleField->GetDouble(h_instance.Get()), static_cast<double>(0.0));
mirror::ArtField* objectField = h_klass->FindDeclaredInstanceField("objectField",
"Ljava/lang/Object;");
@@ -289,8 +289,8 @@
EXPECT_EQ(shortField->GetShort(h_instance.Get()), 0);
EXPECT_EQ(intField->GetInt(h_instance.Get()), 0);
EXPECT_EQ(longField->GetLong(h_instance.Get()), static_cast<int64_t>(0));
- EXPECT_EQ(floatField->GetFloat(h_instance.Get()), static_cast<float>(0.0f));
- EXPECT_EQ(doubleField->GetDouble(h_instance.Get()), static_cast<double>(0.0));
+ EXPECT_FLOAT_EQ(floatField->GetFloat(h_instance.Get()), static_cast<float>(0.0f));
+ EXPECT_DOUBLE_EQ(doubleField->GetDouble(h_instance.Get()), static_cast<double>(0.0));
EXPECT_EQ(objectField->GetObject(h_instance.Get()), nullptr);
}
@@ -356,14 +356,14 @@
mirror::FloatArray* floatArray = floatArrayField->GetObject(h_klass.Get())->AsFloatArray();
ASSERT_TRUE(floatArray != nullptr);
ASSERT_EQ(floatArray->GetLength(), 1);
- ASSERT_EQ(floatArray->GetWithoutChecks(0), static_cast<float>(0.0f));
+ ASSERT_FLOAT_EQ(floatArray->GetWithoutChecks(0), static_cast<float>(0.0f));
mirror::ArtField* doubleArrayField = h_klass->FindDeclaredStaticField("doubleArrayField", "[D");
ASSERT_TRUE(doubleArrayField != nullptr);
mirror::DoubleArray* doubleArray = doubleArrayField->GetObject(h_klass.Get())->AsDoubleArray();
ASSERT_TRUE(doubleArray != nullptr);
ASSERT_EQ(doubleArray->GetLength(), 1);
- ASSERT_EQ(doubleArray->GetWithoutChecks(0), static_cast<double>(0.0f));
+ ASSERT_DOUBLE_EQ(doubleArray->GetWithoutChecks(0), static_cast<double>(0.0f));
mirror::ArtField* objectArrayField = h_klass->FindDeclaredStaticField("objectArrayField",
"[Ljava/lang/Object;");
@@ -404,8 +404,8 @@
EXPECT_EQ(shortArray->GetWithoutChecks(0), 0);
EXPECT_EQ(intArray->GetWithoutChecks(0), 0);
EXPECT_EQ(longArray->GetWithoutChecks(0), static_cast<int64_t>(0));
- EXPECT_EQ(floatArray->GetWithoutChecks(0), static_cast<float>(0.0f));
- EXPECT_EQ(doubleArray->GetWithoutChecks(0), static_cast<double>(0.0f));
+ EXPECT_FLOAT_EQ(floatArray->GetWithoutChecks(0), static_cast<float>(0.0f));
+ EXPECT_DOUBLE_EQ(doubleArray->GetWithoutChecks(0), static_cast<double>(0.0f));
EXPECT_EQ(objectArray->GetWithoutChecks(0), nullptr);
}
diff --git a/test/800-smali/build b/test/800-smali/build
new file mode 100644
index 0000000..1b5a4e3
--- /dev/null
+++ b/test/800-smali/build
@@ -0,0 +1,32 @@
+#!/bin/bash
+#
+# Copyright (C) 2014 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.
+
+# Stop if something fails.
+set -e
+
+# Compile Java classes
+mkdir classes
+${JAVAC} -d classes `find src -name '*.java'`
+${DX} -JXmx256m --debug --dex --output=java_classes.dex classes
+
+# Compile Smali classes
+${SMALI} -JXmx256m --output smali_classes.dex `find src -name '*.smali'`
+
+# Combine files.
+${DXMERGER} classes.dex java_classes.dex smali_classes.dex
+
+# Zip up output.
+zip $TEST_NAME.jar classes.dex
diff --git a/test/800-smali/expected.txt b/test/800-smali/expected.txt
new file mode 100644
index 0000000..468e7a6
--- /dev/null
+++ b/test/800-smali/expected.txt
@@ -0,0 +1,2 @@
+b/17790197
+Done!
diff --git a/test/800-smali/info.txt b/test/800-smali/info.txt
new file mode 100644
index 0000000..cfcc230
--- /dev/null
+++ b/test/800-smali/info.txt
@@ -0,0 +1,4 @@
+Smali-based tests.
+Will compile and run all the smali files in src/ and run the test cases mentioned in src/Main.java.
+
+Obviously needs to run under Dalvik or ART.
diff --git a/test/800-smali/src/Main.java b/test/800-smali/src/Main.java
new file mode 100644
index 0000000..0ef3a9d
--- /dev/null
+++ b/test/800-smali/src/Main.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+import java.lang.reflect.Method;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Smali excercise.
+ */
+public class Main {
+
+ private static class TestCase {
+ public TestCase(String testName, String testClass, String testMethodName, Object[] values,
+ Throwable expectedException, Object expectedReturn) {
+ this.testName = testName;
+ this.testClass = testClass;
+ this.testMethodName = testMethodName;
+ this.values = values;
+ this.expectedException = expectedException;
+ this.expectedReturn = expectedReturn;
+ }
+
+ String testName;
+ String testClass;
+ String testMethodName;
+ Object[] values;
+ Throwable expectedException;
+ Object expectedReturn;
+ }
+
+ private List<TestCase> testCases;
+
+ public Main() {
+ // Create the test cases.
+ testCases = new LinkedList<TestCase>();
+
+ testCases.add(new TestCase("b/17790197", "B17790197", "getInt", null, null, 100));
+ }
+
+ public void runTests() {
+ for (TestCase tc : testCases) {
+ System.out.println(tc.testName);
+ try {
+ runTest(tc);
+ } catch (Exception exc) {
+ exc.printStackTrace(System.out);
+ }
+ }
+ }
+
+ private void runTest(TestCase tc) throws Exception {
+ Class<?> c = Class.forName(tc.testClass);
+
+ Method[] methods = c.getDeclaredMethods();
+
+ // For simplicity we assume that test methods are not overloaded. So searching by name
+ // will give us the method we need to run.
+ Method method = null;
+ for (Method m : methods) {
+ if (m.getName().equals(tc.testMethodName)) {
+ method = m;
+ break;
+ }
+ }
+
+ if (method == null) {
+ throw new IllegalArgumentException("Could not find test method " + tc.testMethodName +
+ " in class " + tc.testClass + " for test " + tc.testName);
+ }
+
+ Exception errorReturn = null;
+ try {
+ Object retValue = method.invoke(null, tc.values);
+ if (tc.expectedException != null) {
+ errorReturn = new IllegalStateException("Expected an exception in test " +
+ tc.testName);
+ }
+ if (tc.expectedReturn == null && retValue != null) {
+ errorReturn = new IllegalStateException("Expected a null result in test " +
+ tc.testName);
+ } else if (tc.expectedReturn != null &&
+ (retValue == null || !tc.expectedReturn.equals(retValue))) {
+ errorReturn = new IllegalStateException("Expected return " + tc.expectedReturn +
+ ", but got " + retValue);
+ }
+ } catch (Exception exc) {
+ if (tc.expectedException == null) {
+ errorReturn = new IllegalStateException("Did not expect exception", exc);
+ } else if (!tc.expectedException.getClass().equals(exc.getClass())) {
+ errorReturn = new IllegalStateException("Expected " +
+ tc.expectedException.getClass().getName() +
+ ", but got " + exc.getClass(), exc);
+ }
+ } finally {
+ if (errorReturn != null) {
+ throw errorReturn;
+ }
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+ Main main = new Main();
+
+ main.runTests();
+
+ System.out.println("Done!");
+ }
+}
diff --git a/test/800-smali/src/b_17790197.smali b/test/800-smali/src/b_17790197.smali
new file mode 100644
index 0000000..7560fcf
--- /dev/null
+++ b/test/800-smali/src/b_17790197.smali
@@ -0,0 +1,17 @@
+.class public LB17790197;
+
+.super Ljava/lang/Object;
+
+.method public static getInt()I
+ .registers 4
+ const/16 v0, 100
+ const/4 v1, 1
+ const/4 v2, 7
+ :loop
+ if-eq v2, v0, :done
+ add-int v2, v2, v1
+ goto :loop
+ :done
+ add-float v3, v0, v1
+ return v2
+.end method
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index 5ca8bec..9082b47 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -36,9 +36,11 @@
# $(1): the test number
define define-build-art-run-test
dmart_target := $(art_run_tests_dir)/art-run-tests/$(1)/touch
-$$(dmart_target): $(DX) $(HOST_OUT_EXECUTABLES)/jasmin
+$$(dmart_target): $(DX) $(HOST_OUT_EXECUTABLES)/jasmin $(HOST_OUT_EXECUTABLES)/smali $(HOST_OUT_EXECUTABLES)/dexmerger
$(hide) rm -rf $$(dir $$@) && mkdir -p $$(dir $$@)
$(hide) DX=$(abspath $(DX)) JASMIN=$(abspath $(HOST_OUT_EXECUTABLES)/jasmin) \
+ SMALI=$(abspath $(HOST_OUT_EXECUTABLES)/smali) \
+ DXMERGER=$(abspath $(HOST_OUT_EXECUTABLES)/dexmerger) \
$(LOCAL_PATH)/run-test --build-only --output-path $$(abspath $$(dir $$@)) $(1)
$(hide) touch $$@
@@ -50,7 +52,7 @@
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := tests
LOCAL_MODULE := art-run-tests
-LOCAL_ADDITIONAL_DEPENDENCIES := $(TEST_ART_RUN_TEST_BUILD_RULES)
+LOCAL_ADDITIONAL_DEPENDENCIES := $(TEST_ART_RUN_TEST_BUILD_RULES) smali dexmerger
# The build system use this flag to pick up files generated by declare-make-art-run-test.
LOCAL_PICKUP_FILES := $(art_run_tests_dir)
@@ -204,7 +206,8 @@
# Tests that are broken with GC stress.
TEST_ART_BROKEN_GCSTRESS_RUN_TESTS := \
- 004-SignalTest
+ 004-SignalTest \
+ 114-ParallelGC
ifneq (,$(filter gcstress,$(GC_TYPES)))
ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(PREBUILD_TYPES), \
@@ -454,9 +457,11 @@
$$(run_test_options)
$$(run_test_rule_name): PRIVATE_RUN_TEST_OPTIONS := $$(run_test_options)
.PHONY: $$(run_test_rule_name)
-$$(run_test_rule_name): $(DX) $(HOST_OUT_EXECUTABLES)/jasmin $$(prereq_rule)
+$$(run_test_rule_name): $(DX) $(HOST_OUT_EXECUTABLES)/jasmin $(HOST_OUT_EXECUTABLES)/smali $(HOST_OUT_EXECUTABLES)/dexmerger $$(prereq_rule)
$(hide) $$(call ART_TEST_SKIP,$$@) && \
DX=$(abspath $(DX)) JASMIN=$(abspath $(HOST_OUT_EXECUTABLES)/jasmin) \
+ SMALI=$(abspath $(HOST_OUT_EXECUTABLES)/smali) \
+ DXMERGER=$(abspath $(HOST_OUT_EXECUTABLES)/dexmerger) \
art/test/run-test $$(PRIVATE_RUN_TEST_OPTIONS) $(9) \
&& $$(call ART_TEST_PASSED,$$@) || $$(call ART_TEST_FAILED,$$@)
$$(hide) (echo $(MAKECMDGOALS) | grep -q $$@ && \
diff --git a/test/run-test b/test/run-test
index 3b5df0d..3e98d6d 100755
--- a/test/run-test
+++ b/test/run-test
@@ -55,6 +55,16 @@
export JASMIN="jasmin"
fi
+# If smali was not set by the environment variable, assume it is in the path.
+if [ -z "$SMALI" ]; then
+ export SMALI="smali"
+fi
+
+# If dexmerger was not set by the environment variable, assume it is in the path.
+if [ -z "$DXMERGER" ]; then
+ export DXMERGER="dexmerger"
+fi
+
info="info.txt"
build="build"