summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.mk4
-rw-r--r--compiler/optimizing/code_generator_x86.cc1
-rw-r--r--compiler/optimizing/load_store_elimination.cc17
-rw-r--r--dex2oat/dex2oat.cc9
-rw-r--r--runtime/arch/arm/quick_entrypoints_arm.S5
-rw-r--r--runtime/arch/arm64/quick_entrypoints_arm64.S74
-rw-r--r--runtime/asm_support.h3
-rw-r--r--runtime/class_linker.cc14
-rw-r--r--runtime/entrypoints/quick/quick_trampoline_entrypoints.cc6
-rw-r--r--runtime/gc/space/image_space_fs.h6
-rw-r--r--runtime/instrumentation.cc5
-rw-r--r--runtime/instrumentation.h8
-rw-r--r--runtime/interpreter/mterp/arm64/op_rem_double_2addr.S2
-rw-r--r--runtime/interpreter/mterp/out/mterp_arm64.S2
-rw-r--r--runtime/native/dalvik_system_VMRuntime.cc6
-rw-r--r--runtime/oat_file_manager.cc19
-rw-r--r--runtime/oat_file_manager.h2
-rw-r--r--runtime/runtime.cc4
-rw-r--r--runtime/runtime.h11
-rw-r--r--runtime/thread_list.cc14
-rw-r--r--runtime/thread_list.h2
-rw-r--r--runtime/verifier/method_verifier.cc10
-rw-r--r--test/003-omnibus-opcodes/src/FloatMath.java50
-rw-r--r--test/586-checker-null-array-get/expected.txt0
-rw-r--r--test/586-checker-null-array-get/info.txt3
-rw-r--r--test/586-checker-null-array-get/src/Main.java42
-rw-r--r--test/974-verify-interface-super/expected.txt1
-rw-r--r--test/974-verify-interface-super/info.txt3
-rw-r--r--test/974-verify-interface-super/smali/base.smali31
-rw-r--r--test/974-verify-interface-super/smali/iface.smali22
-rw-r--r--test/974-verify-interface-super/smali/main.smali40
-rwxr-xr-xtest/etc/run-test-jar4
-rwxr-xr-xtest/run-test2
33 files changed, 384 insertions, 38 deletions
diff --git a/Android.mk b/Android.mk
index e89f6178e7..a518d2f56f 100644
--- a/Android.mk
+++ b/Android.mk
@@ -270,9 +270,9 @@ endif
test-art-host-dexdump: $(addprefix $(HOST_OUT_EXECUTABLES)/, dexdump2 dexlist)
ANDROID_HOST_OUT=$(realpath $(HOST_OUT)) art/test/dexdump/run-all-tests
-# Valgrind. Currently only 32b gtests. TODO: change this from 32-bit only to both 32-bit and 64-bit.
+# Valgrind.
.PHONY: valgrind-test-art-host
-valgrind-test-art-host: valgrind-test-art-host-gtest32
+valgrind-test-art-host: valgrind-test-art-host-gtest
$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
.PHONY: valgrind-test-art-host32
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 9acaa1d000..3b643a3c4f 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -4796,6 +4796,7 @@ void InstructionCodeGeneratorX86::HandleFieldSet(HInstruction* instruction,
int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
__ movl(Address(base, offset), Immediate(v));
} else {
+ DCHECK(value.IsRegister()) << value;
__ movl(Address(base, offset), value.AsRegister<Register>());
}
break;
diff --git a/compiler/optimizing/load_store_elimination.cc b/compiler/optimizing/load_store_elimination.cc
index 8eaac0bbd3..561dcfbb1f 100644
--- a/compiler/optimizing/load_store_elimination.cc
+++ b/compiler/optimizing/load_store_elimination.cc
@@ -728,6 +728,23 @@ class LSEVisitor : public HGraphVisitor {
// This acts like GVN but with better aliasing analysis.
heap_values[idx] = instruction;
} else {
+ if (Primitive::PrimitiveKind(heap_value->GetType())
+ != Primitive::PrimitiveKind(instruction->GetType())) {
+ // The only situation where the same heap location has different type is when
+ // we do an array get from a null constant. In order to stay properly typed
+ // we do not merge the array gets.
+ if (kIsDebugBuild) {
+ DCHECK(heap_value->IsArrayGet()) << heap_value->DebugName();
+ DCHECK(instruction->IsArrayGet()) << instruction->DebugName();
+ HInstruction* array = instruction->AsArrayGet()->GetArray();
+ DCHECK(array->IsNullCheck()) << array->DebugName();
+ DCHECK(array->InputAt(0)->IsNullConstant()) << array->InputAt(0)->DebugName();
+ array = heap_value->AsArrayGet()->GetArray();
+ DCHECK(array->IsNullCheck()) << array->DebugName();
+ DCHECK(array->InputAt(0)->IsNullConstant()) << array->InputAt(0)->DebugName();
+ }
+ return;
+ }
removed_loads_.push_back(instruction);
substitute_instructions_for_loads_.push_back(heap_value);
TryRemovingNullCheck(instruction);
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index a5d0c2797e..298101115d 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -255,6 +255,7 @@ NO_RETURN static void Usage(const char* fmt, ...) {
UsageError("");
UsageError(" --compiler-filter="
"(verify-none"
+ "|verify-at-runtime"
"|interpret-only"
"|space"
"|balanced"
@@ -287,8 +288,8 @@ NO_RETURN static void Usage(const char* fmt, ...) {
UsageError("");
UsageError(" --num-dex-methods=<method-count>: threshold size for a small dex file for");
UsageError(" compiler filter tuning. If the input has fewer than this many methods");
- UsageError(" and the filter is not interpret-only or verify-none, overrides the");
- UsageError(" filter to use speed");
+ UsageError(" and the filter is not interpret-only or verify-none or verify-at-runtime, ");
+ UsageError(" overrides the filter to use speed");
UsageError(" Example: --num-dex-method=%d", CompilerOptions::kDefaultNumDexMethodsThreshold);
UsageError(" Default: %d", CompilerOptions::kDefaultNumDexMethodsThreshold);
UsageError("");
@@ -1449,8 +1450,8 @@ class Dex2Oat FINAL {
}
/*
- * If we're not in interpret-only or verify-none mode, go ahead and compile small applications.
- * Don't bother to check if we're doing the image.
+ * If we're not in interpret-only or verify-none or verify-at-runtime mode, go ahead and
+ * compile small applications. Don't bother to check if we're doing the image.
*/
if (!IsBootImage() &&
compiler_options_->IsCompilationEnabled() &&
diff --git a/runtime/arch/arm/quick_entrypoints_arm.S b/runtime/arch/arm/quick_entrypoints_arm.S
index 64135d8f77..82ec0b7c09 100644
--- a/runtime/arch/arm/quick_entrypoints_arm.S
+++ b/runtime/arch/arm/quick_entrypoints_arm.S
@@ -1125,9 +1125,8 @@ ENTRY art_quick_alloc_object_tlab
// r0: type_idx/return value, r1: ArtMethod*, r9: Thread::Current
// r2, r3, r12: free.
#if defined(USE_READ_BARRIER)
- eor r0, r0, r0 // Read barrier not supported here.
- sub r0, r0, #1 // Return -1.
- bx lr
+ mvn r0, #0 // Read barrier not supported here.
+ bx lr // Return -1.
#endif
ldr r2, [r1, #ART_METHOD_DEX_CACHE_TYPES_OFFSET_32] // Load dex cache resolved types array
// Load the class (r2)
diff --git a/runtime/arch/arm64/quick_entrypoints_arm64.S b/runtime/arch/arm64/quick_entrypoints_arm64.S
index e4c255809b..65d5b463c7 100644
--- a/runtime/arch/arm64/quick_entrypoints_arm64.S
+++ b/runtime/arch/arm64/quick_entrypoints_arm64.S
@@ -1638,7 +1638,79 @@ ENTRY art_quick_alloc_object_rosalloc
RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
END art_quick_alloc_object_rosalloc
-GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_tlab, TLAB)
+// A hand-written override for GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_tlab, TLAB).
+ENTRY art_quick_alloc_object_tlab
+ // Fast path tlab allocation.
+ // x0: type_idx/return value, x1: ArtMethod*, xSELF(x19): Thread::Current
+ // x2-x7: free.
+#if defined(USE_READ_BARRIER)
+ mvn x0, xzr // Read barrier not supported here.
+ ret // Return -1.
+#endif
+ ldr x2, [x1, #ART_METHOD_DEX_CACHE_TYPES_OFFSET_64] // Load dex cache resolved types array
+ // Load the class (x2)
+ ldr w2, [x2, x0, lsl #COMPRESSED_REFERENCE_SIZE_SHIFT]
+ cbz x2, .Lart_quick_alloc_object_tlab_slow_path // Check null class
+ // Check class status.
+ ldr w3, [x2, #MIRROR_CLASS_STATUS_OFFSET]
+ cmp x3, #MIRROR_CLASS_STATUS_INITIALIZED
+ bne .Lart_quick_alloc_object_tlab_slow_path
+ // Add a fake dependence from the
+ // following access flag and size
+ // loads to the status load.
+ // This is to prevent those loads
+ // from being reordered above the
+ // status load and reading wrong
+ // values (an alternative is to use
+ // a load-acquire for the status).
+ eor x3, x3, x3
+ add x2, x2, x3
+ // Check access flags has
+ // kAccClassIsFinalizable.
+ ldr w3, [x2, #MIRROR_CLASS_ACCESS_FLAGS_OFFSET]
+ tbnz x3, #ACCESS_FLAGS_CLASS_IS_FINALIZABLE_BIT, .Lart_quick_alloc_object_tlab_slow_path
+ // Load thread_local_pos (x4) and
+ // thread_local_end (x5).
+ ldr x4, [xSELF, #THREAD_LOCAL_POS_OFFSET]
+ ldr x5, [xSELF, #THREAD_LOCAL_END_OFFSET]
+ sub x6, x5, x4 // Compute the remaining buf size.
+ ldr w7, [x2, #MIRROR_CLASS_OBJECT_SIZE_OFFSET] // Load the object size (x7).
+ cmp x7, x6 // Check if it fits. OK to do this
+ // before rounding up the object size
+ // assuming the buf size alignment.
+ bhi .Lart_quick_alloc_object_tlab_slow_path
+ // "Point of no slow path". Won't go to the slow path from here on. OK to clobber x0 and x1.
+ // Round up the object size by the
+ // object alignment. (addr + 7) & ~7.
+ add x7, x7, #OBJECT_ALIGNMENT_MASK
+ and x7, x7, #OBJECT_ALIGNMENT_MASK_TOGGLED
+ // Move old thread_local_pos to x0
+ // for the return value.
+ mov x0, x4
+ add x5, x0, x7
+ str x5, [xSELF, #THREAD_LOCAL_POS_OFFSET] // Store new thread_local_pos.
+ ldr x5, [xSELF, #THREAD_LOCAL_OBJECTS_OFFSET] // Increment thread_local_objects.
+ add x5, x5, #1
+ str x5, [xSELF, #THREAD_LOCAL_OBJECTS_OFFSET]
+ POISON_HEAP_REF w2
+ str w2, [x0, #MIRROR_OBJECT_CLASS_OFFSET] // Store the class pointer.
+ // Fence. This is "ish" not "ishst" so
+ // that the code after this allocation
+ // site will see the right values in
+ // the fields of the class.
+ // Alternatively we could use "ishst"
+ // if we use load-acquire for the
+ // class status load.)
+ dmb ish
+ ret
+.Lart_quick_alloc_object_tlab_slow_path:
+ SETUP_REFS_ONLY_CALLEE_SAVE_FRAME // Save callee saves in case of GC.
+ mov x2, xSELF // Pass Thread::Current.
+ bl artAllocObjectFromCodeTLAB // (uint32_t type_idx, Method* method, Thread*)
+ RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
+ RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
+END art_quick_alloc_object_tlab
+
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_region_tlab, RegionTLAB)
/*
diff --git a/runtime/asm_support.h b/runtime/asm_support.h
index d5f0dffc38..1f24f45fd0 100644
--- a/runtime/asm_support.h
+++ b/runtime/asm_support.h
@@ -230,6 +230,9 @@ ADD_TEST_EQ(static_cast<uint32_t>(MIRROR_CLASS_STATUS_INITIALIZED),
#define ACCESS_FLAGS_CLASS_IS_FINALIZABLE 0x80000000
ADD_TEST_EQ(static_cast<uint32_t>(ACCESS_FLAGS_CLASS_IS_FINALIZABLE),
static_cast<uint32_t>(art::kAccClassIsFinalizable))
+#define ACCESS_FLAGS_CLASS_IS_FINALIZABLE_BIT 31
+ADD_TEST_EQ(static_cast<uint32_t>(ACCESS_FLAGS_CLASS_IS_FINALIZABLE),
+ static_cast<uint32_t>(1U << ACCESS_FLAGS_CLASS_IS_FINALIZABLE_BIT))
// Array offsets.
#define MIRROR_ARRAY_LENGTH_OFFSET MIRROR_OBJECT_HEADER_SIZE
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 902ba03ea5..d8e309d57e 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -4270,10 +4270,18 @@ void ClassLinker::CreateProxyMethod(Handle<mirror::Class> klass, ArtMethod* prot
DCHECK(out != nullptr);
out->CopyFrom(prototype, image_pointer_size_);
- // Set class to be the concrete proxy class and clear the abstract flag, modify exceptions to
- // the intersection of throw exceptions as defined in Proxy
+ // Set class to be the concrete proxy class.
out->SetDeclaringClass(klass.Get());
- out->SetAccessFlags((out->GetAccessFlags() & ~kAccAbstract) | kAccFinal);
+ // Clear the abstract, default and conflict flags to ensure that defaults aren't picked in
+ // preference to the invocation handler.
+ const uint32_t kRemoveFlags = kAccAbstract | kAccDefault | kAccDefaultConflict;
+ // Make the method final.
+ const uint32_t kAddFlags = kAccFinal;
+ out->SetAccessFlags((out->GetAccessFlags() & ~kRemoveFlags) | kAddFlags);
+
+ // Clear the dex_code_item_offset_. It needs to be 0 since proxy methods have no CodeItems but the
+ // method they copy might (if it's a default method).
+ out->SetCodeItemOffset(0);
// At runtime the method looks like a reference and argument saving method, clone the code
// related parameters from this method.
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index 24986253f7..7005aa5548 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -653,13 +653,13 @@ extern "C" uint64_t artQuickToInterpreterBridge(ArtMethod* method, Thread* self,
JValue tmp_value;
ShadowFrame* deopt_frame = self->PopStackedShadowFrame(
StackedShadowFrameType::kSingleFrameDeoptimizationShadowFrame, false);
- const DexFile::CodeItem* code_item = method->GetCodeItem();
- DCHECK(code_item != nullptr) << PrettyMethod(method);
ManagedStack fragment;
DCHECK(!method->IsNative()) << PrettyMethod(method);
uint32_t shorty_len = 0;
- auto* non_proxy_method = method->GetInterfaceMethodIfProxy(sizeof(void*));
+ ArtMethod* non_proxy_method = method->GetInterfaceMethodIfProxy(sizeof(void*));
+ const DexFile::CodeItem* code_item = non_proxy_method->GetCodeItem();
+ DCHECK(code_item != nullptr) << PrettyMethod(method);
const char* shorty = non_proxy_method->GetShorty(&shorty_len);
JValue result;
diff --git a/runtime/gc/space/image_space_fs.h b/runtime/gc/space/image_space_fs.h
index ec4bf92a2a..5237466c00 100644
--- a/runtime/gc/space/image_space_fs.h
+++ b/runtime/gc/space/image_space_fs.h
@@ -26,6 +26,7 @@
#include "base/unix_file/fd_file.h"
#include "globals.h"
#include "os.h"
+#include "runtime.h"
#include "utils.h"
namespace art {
@@ -200,6 +201,11 @@ static void PruneDalvikCache(InstructionSet isa) {
impl::DeleteDirectoryContents(GetDalvikCacheOrDie(".", false), false);
// Prune /data/dalvik-cache/<isa>.
impl::DeleteDirectoryContents(GetDalvikCacheOrDie(GetInstructionSetString(isa), false), false);
+
+ // Be defensive. There should be a runtime created here, but this may be called in a test.
+ if (Runtime::Current() != nullptr) {
+ Runtime::Current()->SetPrunedDalvikCache(true);
+ }
}
// We write out an empty file to the zygote's ISA specific cache dir at the start of
diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc
index b107b72b55..a0c6bfbd83 100644
--- a/runtime/instrumentation.cc
+++ b/runtime/instrumentation.cc
@@ -83,7 +83,8 @@ Instrumentation::Instrumentation()
deoptimized_methods_lock_("deoptimized methods lock"),
deoptimization_enabled_(false),
interpreter_handler_table_(kMainHandlerTable),
- quick_alloc_entry_points_instrumentation_counter_(0) {
+ quick_alloc_entry_points_instrumentation_counter_(0),
+ alloc_entrypoints_instrumented_(false) {
}
void Instrumentation::InstallStubsForClass(mirror::Class* klass) {
@@ -642,10 +643,12 @@ void Instrumentation::SetEntrypointsInstrumented(bool instrumented) {
MutexLock mu(self, *Locks::runtime_shutdown_lock_);
SetQuickAllocEntryPointsInstrumented(instrumented);
ResetQuickAllocEntryPoints();
+ alloc_entrypoints_instrumented_ = instrumented;
} else {
MutexLock mu(self, *Locks::runtime_shutdown_lock_);
SetQuickAllocEntryPointsInstrumented(instrumented);
ResetQuickAllocEntryPoints();
+ alloc_entrypoints_instrumented_ = instrumented;
}
}
diff --git a/runtime/instrumentation.h b/runtime/instrumentation.h
index b3cdb410f3..d07f47bf29 100644
--- a/runtime/instrumentation.h
+++ b/runtime/instrumentation.h
@@ -422,7 +422,7 @@ class Instrumentation {
// Does not hold lock, used to check if someone changed from not instrumented to instrumented
// during a GC suspend point.
bool AllocEntrypointsInstrumented() const SHARED_REQUIRES(Locks::mutator_lock_) {
- return quick_alloc_entry_points_instrumentation_counter_ > 0;
+ return alloc_entrypoints_instrumented_;
}
private:
@@ -579,6 +579,12 @@ class Instrumentation {
// Greater than 0 if quick alloc entry points instrumented.
size_t quick_alloc_entry_points_instrumentation_counter_;
+
+ // alloc_entrypoints_instrumented_ is only updated with all the threads suspended, this is done
+ // to prevent races with the GC where the GC relies on thread suspension only see
+ // alloc_entrypoints_instrumented_ change during suspend points.
+ bool alloc_entrypoints_instrumented_;
+
friend class InstrumentationTest; // For GetCurrentInstrumentationLevel and ConfigureStubs.
DISALLOW_COPY_AND_ASSIGN(Instrumentation);
diff --git a/runtime/interpreter/mterp/arm64/op_rem_double_2addr.S b/runtime/interpreter/mterp/arm64/op_rem_double_2addr.S
index db18aa7ee2..9868f4123a 100644
--- a/runtime/interpreter/mterp/arm64/op_rem_double_2addr.S
+++ b/runtime/interpreter/mterp/arm64/op_rem_double_2addr.S
@@ -3,9 +3,9 @@
ubfx w2, wINST, #8, #4 // w2<- A
GET_VREG_WIDE d1, w1 // d1<- vB
GET_VREG_WIDE d0, w2 // d0<- vA
- FETCH_ADVANCE_INST 1 // advance rPC, load rINST
bl fmod
ubfx w2, wINST, #8, #4 // w2<- A (need to reload - killed across call)
+ FETCH_ADVANCE_INST 1 // advance rPC, load rINST
GET_INST_OPCODE ip // extract opcode from rINST
SET_VREG_WIDE d0, w2 // vAA<- result
GOTO_OPCODE ip // jump to next instruction
diff --git a/runtime/interpreter/mterp/out/mterp_arm64.S b/runtime/interpreter/mterp/out/mterp_arm64.S
index cdb27e89e6..6ae59d857f 100644
--- a/runtime/interpreter/mterp/out/mterp_arm64.S
+++ b/runtime/interpreter/mterp/out/mterp_arm64.S
@@ -5984,9 +5984,9 @@ artMterpAsmInstructionStart = .L_op_nop
ubfx w2, wINST, #8, #4 // w2<- A
GET_VREG_WIDE d1, w1 // d1<- vB
GET_VREG_WIDE d0, w2 // d0<- vA
- FETCH_ADVANCE_INST 1 // advance rPC, load rINST
bl fmod
ubfx w2, wINST, #8, #4 // w2<- A (need to reload - killed across call)
+ FETCH_ADVANCE_INST 1 // advance rPC, load rINST
GET_INST_OPCODE ip // extract opcode from rINST
SET_VREG_WIDE d0, w2 // vAA<- result
GOTO_OPCODE ip // jump to next instruction
diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc
index f6b2f21515..4ac28ae593 100644
--- a/runtime/native/dalvik_system_VMRuntime.cc
+++ b/runtime/native/dalvik_system_VMRuntime.cc
@@ -622,6 +622,11 @@ static jstring VMRuntime_getCurrentInstructionSet(JNIEnv* env, jclass) {
return env->NewStringUTF(GetInstructionSetString(kRuntimeISA));
}
+static jboolean VMRuntime_didPruneDalvikCache(JNIEnv* env ATTRIBUTE_UNUSED,
+ jclass klass ATTRIBUTE_UNUSED) {
+ return Runtime::Current()->GetPrunedDalvikCache() ? JNI_TRUE : JNI_FALSE;
+}
+
static JNINativeMethod gMethods[] = {
NATIVE_METHOD(VMRuntime, addressOf, "!(Ljava/lang/Object;)J"),
NATIVE_METHOD(VMRuntime, bootClassPath, "()Ljava/lang/String;"),
@@ -657,6 +662,7 @@ static JNINativeMethod gMethods[] = {
"(Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)V"),
NATIVE_METHOD(VMRuntime, isBootClassPathOnDisk, "(Ljava/lang/String;)Z"),
NATIVE_METHOD(VMRuntime, getCurrentInstructionSet, "()Ljava/lang/String;"),
+ NATIVE_METHOD(VMRuntime, didPruneDalvikCache, "()Z"),
};
void register_dalvik_system_VMRuntime(JNIEnv* env) {
diff --git a/runtime/oat_file_manager.cc b/runtime/oat_file_manager.cc
index e57125bef1..3ec3826374 100644
--- a/runtime/oat_file_manager.cc
+++ b/runtime/oat_file_manager.cc
@@ -477,4 +477,23 @@ void OatFileManager::UnRegisterOatFileLocation(const std::string& oat_location)
}
}
+void OatFileManager::DumpForSigQuit(std::ostream& os) {
+ ReaderMutexLock mu(Thread::Current(), *Locks::oat_file_manager_lock_);
+ std::vector<const OatFile*> boot_oat_files = GetBootOatFiles();
+ for (const std::unique_ptr<const OatFile>& oat_file : oat_files_) {
+ if (ContainsElement(boot_oat_files, oat_file.get())) {
+ continue;
+ }
+ // Use "platform-default" if it's neither extract nor profile guided.
+ // Saying 'full' could be misleading if for example the platform uses
+ // compiler filters.
+ const char* status = oat_file->IsExtractOnly()
+ ? OatHeader::kExtractOnlyValue
+ : oat_file->IsProfileGuideCompiled()
+ ? OatHeader::kProfileGuideCompiledValue
+ : "platform-default";
+ os << oat_file->GetLocation() << ": " << status << "\n";
+ }
+}
+
} // namespace art
diff --git a/runtime/oat_file_manager.h b/runtime/oat_file_manager.h
index c508c4bf07..a541d1022b 100644
--- a/runtime/oat_file_manager.h
+++ b/runtime/oat_file_manager.h
@@ -108,6 +108,8 @@ class OatFileManager {
/*out*/ std::vector<std::string>* error_msgs)
REQUIRES(!Locks::oat_file_manager_lock_, !Locks::mutator_lock_);
+ void DumpForSigQuit(std::ostream& os);
+
private:
// Check for duplicate class definitions of the given oat file against all open oat files.
// Return true if there are any class definition collisions in the oat_file.
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 78e00fdbde..5284c9377e 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -208,7 +208,8 @@ Runtime::Runtime()
experimental_flags_(ExperimentalFlags::kNone),
oat_file_manager_(nullptr),
is_low_memory_mode_(false),
- safe_mode_(false) {
+ safe_mode_(false),
+ pruned_dalvik_cache_(false) {
CheckAsmSupportOffsetsAndSizes();
std::fill(callee_save_methods_, callee_save_methods_ + arraysize(callee_save_methods_), 0u);
interpreter::CheckInterpreterAsmConstants();
@@ -1363,6 +1364,7 @@ void Runtime::DumpForSigQuit(std::ostream& os) {
GetInternTable()->DumpForSigQuit(os);
GetJavaVM()->DumpForSigQuit(os);
GetHeap()->DumpForSigQuit(os);
+ oat_file_manager_->DumpForSigQuit(os);
if (GetJit() != nullptr) {
GetJit()->DumpForSigQuit(os);
} else {
diff --git a/runtime/runtime.h b/runtime/runtime.h
index aff7c067d3..36ad7f1087 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -618,6 +618,14 @@ class Runtime {
return dump_native_stack_on_sig_quit_;
}
+ bool GetPrunedDalvikCache() const {
+ return pruned_dalvik_cache_;
+ }
+
+ void SetPrunedDalvikCache(bool pruned) {
+ pruned_dalvik_cache_ = pruned;
+ }
+
private:
static void InitPlatformSignalHandlers();
@@ -833,6 +841,9 @@ class Runtime {
// Whether threads should dump their native stack on SIGQUIT.
bool dump_native_stack_on_sig_quit_;
+ // Whether the dalvik cache was pruned when initializing the runtime.
+ bool pruned_dalvik_cache_;
+
DISALLOW_COPY_AND_ASSIGN(Runtime);
};
std::ostream& operator<<(std::ostream& os, const Runtime::CalleeSaveType& rhs);
diff --git a/runtime/thread_list.cc b/runtime/thread_list.cc
index afb11d33e9..a9ce056fd9 100644
--- a/runtime/thread_list.cc
+++ b/runtime/thread_list.cc
@@ -133,22 +133,24 @@ void ThreadList::DumpForSigQuit(std::ostream& os) {
suspend_all_historam_.PrintConfidenceIntervals(os, 0.99, data); // Dump time to suspend.
}
}
- Dump(os, Runtime::Current()->GetDumpNativeStackOnSigQuit());
- DumpUnattachedThreads(os);
+ bool dump_native_stack = Runtime::Current()->GetDumpNativeStackOnSigQuit();
+ Dump(os, dump_native_stack);
+ DumpUnattachedThreads(os, dump_native_stack);
}
-static void DumpUnattachedThread(std::ostream& os, pid_t tid) NO_THREAD_SAFETY_ANALYSIS {
+static void DumpUnattachedThread(std::ostream& os, pid_t tid, bool dump_native_stack)
+ NO_THREAD_SAFETY_ANALYSIS {
// TODO: No thread safety analysis as DumpState with a null thread won't access fields, should
// refactor DumpState to avoid skipping analysis.
Thread::DumpState(os, nullptr, tid);
DumpKernelStack(os, tid, " kernel: ", false);
- if (kDumpUnattachedThreadNativeStack) {
+ if (dump_native_stack && kDumpUnattachedThreadNativeStack) {
DumpNativeStack(os, tid, nullptr, " native: ");
}
os << "\n";
}
-void ThreadList::DumpUnattachedThreads(std::ostream& os) {
+void ThreadList::DumpUnattachedThreads(std::ostream& os, bool dump_native_stack) {
DIR* d = opendir("/proc/self/task");
if (!d) {
return;
@@ -166,7 +168,7 @@ void ThreadList::DumpUnattachedThreads(std::ostream& os) {
contains = Contains(tid);
}
if (!contains) {
- DumpUnattachedThread(os, tid);
+ DumpUnattachedThread(os, tid, dump_native_stack);
}
}
}
diff --git a/runtime/thread_list.h b/runtime/thread_list.h
index 363cab83f4..f97ecd34a5 100644
--- a/runtime/thread_list.h
+++ b/runtime/thread_list.h
@@ -161,7 +161,7 @@ class ThreadList {
size_t RunCheckpoint(Closure* checkpoint_function, bool includeSuspended)
REQUIRES(!Locks::thread_list_lock_, !Locks::thread_suspend_count_lock_);
- void DumpUnattachedThreads(std::ostream& os)
+ void DumpUnattachedThreads(std::ostream& os, bool dump_native_stack)
REQUIRES(!Locks::thread_list_lock_);
void SuspendAllDaemonThreadsForShutdown()
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 4019656c93..537d9c9311 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -3992,13 +3992,17 @@ ArtMethod* MethodVerifier::VerifyInvocationArgs(
// TODO Can we verify anything else.
if (class_idx == class_def_->class_idx_) {
Fail(VERIFY_ERROR_CLASS_CHANGE) << "Cannot invoke-super on self as interface";
+ return nullptr;
}
// TODO Revisit whether we want to allow invoke-super on direct interfaces only like the JLS
// does.
- mirror::Class* this_class = GetDeclaringClass().GetClass();
- if (!reference_class->IsAssignableFrom(this_class)) {
+ if (!GetDeclaringClass().HasClass()) {
+ Fail(VERIFY_ERROR_NO_CLASS) << "Unable to resolve the full class of 'this' used in an"
+ << "interface invoke-super";
+ return nullptr;
+ } else if (!reference_class->IsAssignableFrom(GetDeclaringClass().GetClass())) {
Fail(VERIFY_ERROR_CLASS_CHANGE)
- << "invoke-super in " << PrettyClass(this_class) << " in method "
+ << "invoke-super in " << PrettyClass(GetDeclaringClass().GetClass()) << " in method "
<< PrettyMethod(dex_method_idx_, *dex_file_) << " to method "
<< PrettyMethod(method_idx, *dex_file_) << " references "
<< "non-super-interface type " << PrettyClass(reference_class);
diff --git a/test/003-omnibus-opcodes/src/FloatMath.java b/test/003-omnibus-opcodes/src/FloatMath.java
index 96befe9cdc..fcdb4fe305 100644
--- a/test/003-omnibus-opcodes/src/FloatMath.java
+++ b/test/003-omnibus-opcodes/src/FloatMath.java
@@ -135,7 +135,8 @@ public class FloatMath {
static float[] floatOperTest(float x, float y) {
System.out.println("FloatMath.floatOperTest");
- float[] results = new float[9];
+ float[] results = new float[10];
+ float tmp;
/* this seems to generate "op-float" instructions */
results[0] = x + y;
@@ -145,7 +146,21 @@ public class FloatMath {
results[4] = x % -y;
/* this seems to generate "op-float/2addr" instructions */
- results[8] = x + (((((x + y) - y) * y) / y) % y);
+ tmp = x;
+ tmp += y;
+ results[5] = tmp;
+ tmp = x;
+ tmp -= y;
+ results[6] = tmp;
+ tmp = x;
+ tmp *= y;
+ results[7] = tmp;
+ tmp = x;
+ tmp /= y;
+ results[8] = tmp;
+ tmp = x;
+ tmp %= -y;
+ results[9] = tmp;
return results;
}
@@ -155,7 +170,11 @@ public class FloatMath {
Main.assertTrue(results[2] > -210000.01f && results[2] < -209999.99f);
Main.assertTrue(results[3] > -23333.34f && results[3] < -23333.32f);
Main.assertTrue(results[4] > 0.999f && results[4] < 1.001f);
- Main.assertTrue(results[8] > 70000.99f && results[8] < 70001.01f);
+ Main.assertTrue(results[5] > 69996.99f && results[5] < 69997.01f);
+ Main.assertTrue(results[6] > 70002.99f && results[6] < 70003.01f);
+ Main.assertTrue(results[7] > -210000.01f && results[7] < -209999.99f);
+ Main.assertTrue(results[8] > -23333.34f && results[8] < -23333.32f);
+ Main.assertTrue(results[9] > 0.999f && results[9] < 1.001f);
}
/*
@@ -165,7 +184,8 @@ public class FloatMath {
static double[] doubleOperTest(double x, double y) {
System.out.println("FloatMath.doubleOperTest");
- double[] results = new double[9];
+ double[] results = new double[10];
+ double tmp;
/* this seems to generate "op-double" instructions */
results[0] = x + y;
@@ -175,7 +195,21 @@ public class FloatMath {
results[4] = x % -y;
/* this seems to generate "op-double/2addr" instructions */
- results[8] = x + (((((x + y) - y) * y) / y) % y);
+ tmp = x;
+ tmp += y;
+ results[5] = tmp;
+ tmp = x;
+ tmp -= y;
+ results[6] = tmp;
+ tmp = x;
+ tmp *= y;
+ results[7] = tmp;
+ tmp = x;
+ tmp /= y;
+ results[8] = tmp;
+ tmp = x;
+ tmp %= -y;
+ results[9] = tmp;
return results;
}
@@ -185,7 +219,11 @@ public class FloatMath {
Main.assertTrue(results[2] > -210000.01 && results[2] < -209999.99);
Main.assertTrue(results[3] > -23333.34 && results[3] < -23333.32);
Main.assertTrue(results[4] > 0.999 && results[4] < 1.001);
- Main.assertTrue(results[8] > 70000.99 && results[8] < 70001.01);
+ Main.assertTrue(results[5] > 69996.99 && results[5] < 69997.01);
+ Main.assertTrue(results[6] > 70002.99 && results[6] < 70003.01);
+ Main.assertTrue(results[7] > -210000.01 && results[7] < -209999.99);
+ Main.assertTrue(results[8] > -23333.34 && results[8] < -23333.32);
+ Main.assertTrue(results[9] > 0.999 && results[9] < 1.001);
}
/*
diff --git a/test/586-checker-null-array-get/expected.txt b/test/586-checker-null-array-get/expected.txt
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/586-checker-null-array-get/expected.txt
diff --git a/test/586-checker-null-array-get/info.txt b/test/586-checker-null-array-get/info.txt
new file mode 100644
index 0000000000..81b42e9789
--- /dev/null
+++ b/test/586-checker-null-array-get/info.txt
@@ -0,0 +1,3 @@
+Regression test for the load store elimination of optimizing
+that used to merge two array gets that have the same inputs but
+not the same type. Note that this only happens if the array is null.
diff --git a/test/586-checker-null-array-get/src/Main.java b/test/586-checker-null-array-get/src/Main.java
new file mode 100644
index 0000000000..4b03ff28eb
--- /dev/null
+++ b/test/586-checker-null-array-get/src/Main.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class Main {
+ public static Object[] getObjectArray() { return null; }
+ public static long[] getLongArray() { return null; }
+
+ public static void main(String[] args) {
+ try {
+ foo();
+ throw new Error("Expected NullPointerException");
+ } catch (NullPointerException e) {
+ // Expected.
+ }
+ }
+
+ /// CHECK-START: void Main.foo() load_store_elimination (after)
+ /// CHECK-DAG: <<Null:l\d+>> NullConstant
+ /// CHECK-DAG: <<Check:l\d+>> NullCheck [<<Null>>]
+ /// CHECK-DAG: <<Get1:j\d+>> ArrayGet [<<Check>>,{{i\d+}}]
+ /// CHECK-DAG: <<Get2:l\d+>> ArrayGet [<<Check>>,{{i\d+}}]
+ public static void foo() {
+ longField = getLongArray()[0];
+ objectField = getObjectArray()[0];
+ }
+
+ public static long longField;
+ public static Object objectField;
+}
diff --git a/test/974-verify-interface-super/expected.txt b/test/974-verify-interface-super/expected.txt
new file mode 100644
index 0000000000..7ba7491891
--- /dev/null
+++ b/test/974-verify-interface-super/expected.txt
@@ -0,0 +1 @@
+OK. No exception before invoke!
diff --git a/test/974-verify-interface-super/info.txt b/test/974-verify-interface-super/info.txt
new file mode 100644
index 0000000000..c5ff1f69f1
--- /dev/null
+++ b/test/974-verify-interface-super/info.txt
@@ -0,0 +1,3 @@
+Test that we do the right thing with invoke-super on interfaces when there are
+verifier errors.
+
diff --git a/test/974-verify-interface-super/smali/base.smali b/test/974-verify-interface-super/smali/base.smali
new file mode 100644
index 0000000000..c7875de1d3
--- /dev/null
+++ b/test/974-verify-interface-super/smali/base.smali
@@ -0,0 +1,31 @@
+# Copyright 2016 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.
+
+.class public LBase;
+
+.super La/klass/that/does/not/Exist;
+
+.method public static run()V
+ .locals 4
+ new-instance v0, LBase;
+ invoke-direct {v0}, LBase;-><init>()V
+ invoke-virtual {v0}, LBase;->SayHi()V
+ return-void
+.end method
+
+.method public SayHi()V
+.locals 2
+ invoke-super {p0}, LIface;->SayHi()V
+ return-void
+.end method
diff --git a/test/974-verify-interface-super/smali/iface.smali b/test/974-verify-interface-super/smali/iface.smali
new file mode 100644
index 0000000000..89f9c0beba
--- /dev/null
+++ b/test/974-verify-interface-super/smali/iface.smali
@@ -0,0 +1,22 @@
+# Copyright 2016 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.
+
+.class public abstract interface LIface;
+
+.super Ljava/lang/Object;
+
+.method public SayHi()V
+.locals 0
+ return-void
+.end method
diff --git a/test/974-verify-interface-super/smali/main.smali b/test/974-verify-interface-super/smali/main.smali
new file mode 100644
index 0000000000..be4016c5c1
--- /dev/null
+++ b/test/974-verify-interface-super/smali/main.smali
@@ -0,0 +1,40 @@
+# Copyright 2016 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.
+
+.class public LMain;
+
+.super Ljava/lang/Object;
+
+.method public static main([Ljava/lang/String;)V
+ .locals 4
+ const-string v0, "OK. No exception before invoke!"
+ sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream;
+ invoke-virtual {v1, v0}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V
+ :try_start
+ invoke-static {}, LBase;->run()V
+ const-string v0, "FAIL: no exception!"
+ sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream;
+ invoke-virtual {v1, v0}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V
+ goto :end
+ :try_end
+ .catch Ljava/lang/LinkageError; {:try_start .. :try_end} :end
+ .catch Ljava/lang/Throwable; {:try_start .. :try_end} :error
+ :error
+ move-exception v0
+ sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream;
+ invoke-virtual {v1, v0}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V
+ invoke-virtual {v0}, Ljava/lang/Throwable;->printStackTrace()V
+ :end
+ return-void
+.end method
diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar
index 2db1e6c947..b360f67874 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -66,6 +66,10 @@ while true; do
fi
LIB="$1"
shift
+ elif [ "x$1" = "x--gc-stress" ]; then
+ # Give an extra 5 mins if we are gc-stress.
+ TIME_OUT_VALUE=$((${TIME_OUT_VALUE} + 300))
+ shift
elif [ "x$1" = "x--testlib" ]; then
shift
if [ "x$1" = "x" ]; then
diff --git a/test/run-test b/test/run-test
index 6bb154942c..3350b35783 100755
--- a/test/run-test
+++ b/test/run-test
@@ -389,7 +389,7 @@ if [ "$gc_verify" = "true" ]; then
run_args="${run_args} --runtime-option -Xgc:preverify_rosalloc --runtime-option -Xgc:postverify_rosalloc"
fi
if [ "$gc_stress" = "true" ]; then
- run_args="${run_args} --runtime-option -Xgc:SS,gcstress --runtime-option -Xms2m --runtime-option -Xmx16m"
+ run_args="${run_args} --gc-stress --runtime-option -Xgc:SS,gcstress --runtime-option -Xms2m --runtime-option -Xmx16m"
fi
if [ "$trace" = "true" ]; then
run_args="${run_args} --runtime-option -Xmethod-trace --runtime-option -Xmethod-trace-file-size:2000000"