Merge "Port 311886c6c6fcd3b531531f592d56caab5e2a259c to art." into dalvik-dev
diff --git a/Android.mk b/Android.mk
index 6de5eff..cd96c52 100644
--- a/Android.mk
+++ b/Android.mk
@@ -177,7 +177,7 @@
define declare-oat-target-target
.PHONY: oat-target-$(1)
oat-target-$(1): $(PRODUCT_OUT)/$(1) $(TARGET_BOOT_IMG_OUT) $(DEX2OAT_DEPENDENCY)
- $(DEX2OAT) --runtime-arg -Xms64m --runtime-arg -Xmx64m --boot-image=$(TARGET_BOOT_IMG_OUT) --dex-file=$(PRODUCT_OUT)/$(1) --dex-location=/$(1) --oat-file=$(call art-cache-out,$(1).oat) --host-prefix=$(PRODUCT_OUT)
+ $(DEX2OAT) $(PARALLEL_ART_COMPILE_JOBS) --runtime-arg -Xms64m --runtime-arg -Xmx64m --boot-image=$(TARGET_BOOT_IMG_OUT) --dex-file=$(PRODUCT_OUT)/$(1) --dex-location=/$(1) --oat-file=$(call art-cache-out,$(1).oat) --host-prefix=$(PRODUCT_OUT)
OAT_TARGET_TARGETS += oat-target-$(1)
endef
diff --git a/build/Android.common.mk b/build/Android.common.mk
index e62602c..cec90e6 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -79,8 +79,9 @@
ART_HOST_NON_DEBUG_CFLAGS := $(art_non_debug_cflags)
ART_TARGET_NON_DEBUG_CFLAGS := $(art_non_debug_cflags)
-# TODO: move -fkeep-inline-functions to art_debug_cflags when target gcc > 4.4
+# TODO: move -fkeep-inline-functions to art_debug_cflags when target gcc > 4.4 (and -lsupc++)
ART_HOST_DEBUG_CFLAGS := $(art_debug_cflags) -fkeep-inline-functions
+ART_HOST_DEBUG_LDLIBS := -lsupc++
ifneq ($(HOST_OS),linux)
# Some Mac OS pthread header files are broken with -fkeep-inline-functions.
@@ -89,6 +90,10 @@
ART_TARGET_DEBUG_CFLAGS := $(art_debug_cflags)
+ifeq ($(ART_USE_LLVM_COMPILER),true)
+PARALLEL_ART_COMPILE_JOBS := -j8
+endif
+
DEX2OAT_SRC_FILES := \
src/dex2oat.cc
@@ -96,6 +101,7 @@
src/oatdump.cc \
src/disassembler.cc \
src/disassembler_arm.cc \
+ src/disassembler_mips.cc \
src/disassembler_x86.cc
OATEXEC_SRC_FILES := \
diff --git a/build/Android.libart-compiler-llvm.mk b/build/Android.libart-compiler-llvm.mk
index d52e6d2..c2ecf20 100644
--- a/build/Android.libart-compiler-llvm.mk
+++ b/build/Android.libart-compiler-llvm.mk
@@ -21,7 +21,6 @@
src/compiler_llvm/compilation_unit.cc \
src/compiler_llvm/compiler_llvm.cc \
src/compiler_llvm/dalvik_reg.cc \
- src/compiler_llvm/frontend.cc \
src/compiler_llvm/generated/art_module.cc \
src/compiler_llvm/inferred_reg_category_map.cc \
src/compiler_llvm/ir_builder.cc \
diff --git a/build/Android.libart.mk b/build/Android.libart.mk
index c7a85ef..a6a7070 100644
--- a/build/Android.libart.mk
+++ b/build/Android.libart.mk
@@ -79,6 +79,7 @@
LOCAL_CFLAGS += $(ART_TARGET_DEBUG_CFLAGS)
else # host
LOCAL_CFLAGS += $(ART_HOST_DEBUG_CFLAGS)
+ LOCAL_LDLIBS += $(ART_HOST_DEBUG_LDLIBS)
LOCAL_STATIC_LIBRARIES := libgtest_host
endif
else
@@ -102,7 +103,7 @@
LOCAL_STATIC_LIBRARIES += libcutils
LOCAL_SHARED_LIBRARIES += libz-host
LOCAL_SHARED_LIBRARIES += libdynamic_annotations-host # tsan support
- LOCAL_LDLIBS := -ldl -lpthread
+ LOCAL_LDLIBS += -ldl -lpthread
ifeq ($(HOST_OS),linux)
LOCAL_LDLIBS += -lrt
endif
diff --git a/build/Android.oat.mk b/build/Android.oat.mk
index 05bddf4..372992f 100644
--- a/build/Android.oat.mk
+++ b/build/Android.oat.mk
@@ -53,29 +53,15 @@
HOST_CORE_IMG_OUT := $(HOST_OUT_JAVA_LIBRARIES)/core.art
TARGET_CORE_IMG_OUT := $(ART_TEST_OUT)/core.art
-ifeq ($(ART_USE_LLVM_COMPILER),true)
- $(HOST_CORE_IMG_OUT): $(HOST_CORE_DEX_FILES) $(DEX2OAT_DEPENDENCY)
+$(HOST_CORE_IMG_OUT): $(HOST_CORE_DEX_FILES) $(DEX2OAT_DEPENDENCY)
@echo "host dex2oat: $@ ($?)"
@mkdir -p $(dir $@)
- $(hide) $(DEX2OAT) -j8 --runtime-arg -Xms16m --runtime-arg -Xmx16m --image-classes=$(PRELOADED_CLASSES) $(addprefix --dex-file=,$(HOST_CORE_DEX_FILES)) $(addprefix --dex-location=,$(HOST_CORE_DEX_LOCATIONS)) --oat-file=$(HOST_CORE_OAT_OUT) --oat-location=$(HOST_CORE_OAT) --image=$(HOST_CORE_IMG_OUT) --base=$(IMG_HOST_BASE_ADDRESS) --instruction-set=X86
-else
- $(HOST_CORE_IMG_OUT): $(HOST_CORE_DEX_FILES) $(DEX2OAT_DEPENDENCY)
- @echo "host dex2oat: $@ ($?)"
- @mkdir -p $(dir $@)
- $(hide) $(DEX2OAT) --runtime-arg -Xms16m --runtime-arg -Xmx16m --image-classes=$(PRELOADED_CLASSES) $(addprefix --dex-file=,$(HOST_CORE_DEX_FILES)) $(addprefix --dex-location=,$(HOST_CORE_DEX_LOCATIONS)) --oat-file=$(HOST_CORE_OAT_OUT) --oat-location=$(HOST_CORE_OAT) --image=$(HOST_CORE_IMG_OUT) --base=$(IMG_HOST_BASE_ADDRESS) --instruction-set=X86
-endif
+ $(hide) $(DEX2OAT) $(PARALLEL_ART_COMPILE_JOBS) --runtime-arg -Xms16m --runtime-arg -Xmx16m --image-classes=$(PRELOADED_CLASSES) $(addprefix --dex-file=,$(HOST_CORE_DEX_FILES)) $(addprefix --dex-location=,$(HOST_CORE_DEX_LOCATIONS)) --oat-file=$(HOST_CORE_OAT_OUT) --oat-location=$(HOST_CORE_OAT) --image=$(HOST_CORE_IMG_OUT) --base=$(IMG_HOST_BASE_ADDRESS) --instruction-set=X86
-ifeq ($(ART_USE_LLVM_COMPILER),true)
$(TARGET_CORE_IMG_OUT): $(TARGET_CORE_DEX_FILES) $(DEX2OAT_DEPENDENCY)
@echo "target dex2oat: $@ ($?)"
@mkdir -p $(dir $@)
- $(hide) $(DEX2OAT) -j8 --runtime-arg -Xms16m --runtime-arg -Xmx16m --image-classes=$(PRELOADED_CLASSES) $(addprefix --dex-file=,$(TARGET_CORE_DEX_FILES)) $(addprefix --dex-location=,$(TARGET_CORE_DEX_LOCATIONS)) --oat-file=$(TARGET_CORE_OAT_OUT) --oat-location=$(TARGET_CORE_OAT) --image=$(TARGET_CORE_IMG_OUT) --base=$(IMG_TARGET_BASE_ADDRESS) --host-prefix=$(PRODUCT_OUT)
-else
-$(TARGET_CORE_IMG_OUT): $(TARGET_CORE_DEX_FILES) $(DEX2OAT_DEPENDENCY)
- @echo "target dex2oat: $@ ($?)"
- @mkdir -p $(dir $@)
- $(hide) $(DEX2OAT) --runtime-arg -Xms16m --runtime-arg -Xmx16m --image-classes=$(PRELOADED_CLASSES) $(addprefix --dex-file=,$(TARGET_CORE_DEX_FILES)) $(addprefix --dex-location=,$(TARGET_CORE_DEX_LOCATIONS)) --oat-file=$(TARGET_CORE_OAT_OUT) --oat-location=$(TARGET_CORE_OAT) --image=$(TARGET_CORE_IMG_OUT) --base=$(IMG_TARGET_BASE_ADDRESS) --host-prefix=$(PRODUCT_OUT)
-endif
+ $(hide) $(DEX2OAT) $(PARALLEL_ART_COMPILE_JOBS) --runtime-arg -Xms16m --runtime-arg -Xmx16m --image-classes=$(PRELOADED_CLASSES) $(addprefix --dex-file=,$(TARGET_CORE_DEX_FILES)) $(addprefix --dex-location=,$(TARGET_CORE_DEX_LOCATIONS)) --oat-file=$(TARGET_CORE_OAT_OUT) --oat-location=$(TARGET_CORE_OAT) --image=$(TARGET_CORE_IMG_OUT) --base=$(IMG_TARGET_BASE_ADDRESS) --host-prefix=$(PRODUCT_OUT)
$(HOST_CORE_OAT_OUT): $(HOST_CORE_IMG_OUT)
@@ -91,17 +77,10 @@
TARGET_BOOT_OAT_OUT := $(patsubst %.art,%.oat,$(TARGET_BOOT_IMG_OUT))
TARGET_BOOT_OAT := $(subst $(PRODUCT_OUT),,$(TARGET_BOOT_OAT_OUT))
-ifeq ($(ART_USE_LLVM_COMPILER),true)
- $(TARGET_BOOT_IMG_OUT): $(TARGET_BOOT_DEX_FILES) $(DEX2OAT_DEPENDENCY)
+$(TARGET_BOOT_IMG_OUT): $(TARGET_BOOT_DEX_FILES) $(DEX2OAT_DEPENDENCY)
@echo "target dex2oat: $@ ($?)"
@mkdir -p $(dir $@)
- $(hide) $(DEX2OAT) -j8 --runtime-arg -Xms256m --runtime-arg -Xmx256m --image-classes=$(PRELOADED_CLASSES) $(addprefix --dex-file=,$(TARGET_BOOT_DEX_FILES)) $(addprefix --dex-location=,$(TARGET_BOOT_DEX_LOCATIONS)) --oat-file=$(TARGET_BOOT_OAT_OUT) --oat-location=$(TARGET_BOOT_OAT) --image=$(TARGET_BOOT_IMG_OUT) --base=$(IMG_TARGET_BASE_ADDRESS) --host-prefix=$(PRODUCT_OUT)
-else
- $(TARGET_BOOT_IMG_OUT): $(TARGET_BOOT_DEX_FILES) $(DEX2OAT_DEPENDENCY)
- @echo "target dex2oat: $@ ($?)"
- @mkdir -p $(dir $@)
- $(hide) $(DEX2OAT) --runtime-arg -Xms256m --runtime-arg -Xmx256m --image-classes=$(PRELOADED_CLASSES) $(addprefix --dex-file=,$(TARGET_BOOT_DEX_FILES)) $(addprefix --dex-location=,$(TARGET_BOOT_DEX_LOCATIONS)) --oat-file=$(TARGET_BOOT_OAT_OUT) --oat-location=$(TARGET_BOOT_OAT) --image=$(TARGET_BOOT_IMG_OUT) --base=$(IMG_TARGET_BASE_ADDRESS) --host-prefix=$(PRODUCT_OUT)
-endif
+ $(hide) $(DEX2OAT) $(PARALLEL_ART_COMPILE_JOBS) --runtime-arg -Xms256m --runtime-arg -Xmx256m --image-classes=$(PRELOADED_CLASSES) $(addprefix --dex-file=,$(TARGET_BOOT_DEX_FILES)) $(addprefix --dex-location=,$(TARGET_BOOT_DEX_LOCATIONS)) --oat-file=$(TARGET_BOOT_OAT_OUT) --oat-location=$(TARGET_BOOT_OAT) --image=$(TARGET_BOOT_IMG_OUT) --base=$(IMG_TARGET_BASE_ADDRESS) --host-prefix=$(PRODUCT_OUT)
$(TARGET_BOOT_OAT_OUT): $(TARGET_BOOT_IMG_OUT)
diff --git a/src/atomic.cc b/src/atomic.cc
index 0625f1f..b923f91 100644
--- a/src/atomic.cc
+++ b/src/atomic.cc
@@ -16,73 +16,54 @@
#include "atomic.h"
-#include <sched.h>
+#include <pthread.h>
+
+#include "mutex.h"
+#include "stl_util.h"
+#include "stringprintf.h"
+
+#if defined(__APPLE__)
+#include <libkern/OSAtomic.h>
+#endif
+#if defined(__arm__)
+#include <machine/cpu-features.h>
+#endif
namespace art {
-/*
- * Quasi-atomic 64-bit operations, for platforms that lack the real thing.
- *
- * TODO: unify ARMv6/x86/sh implementations using the to-be-written
- * spin lock implementation. We don't want to rely on mutex innards,
- * and it would be great if all platforms were running the same code.
- */
-
#if defined(HAVE_MACOSX_IPC)
-
-#include <libkern/OSAtomic.h>
-
-#if defined(__ppc__) \
- || defined(__PPC__) \
- || defined(__powerpc__) \
- || defined(__powerpc) \
- || defined(__POWERPC__) \
- || defined(_M_PPC) \
- || defined(__PPC)
-#define NEED_QUASIATOMICS 1
-#else
-
-int QuasiAtomicCas64(int64_t old_value, int64_t new_value, volatile int64_t* addr) {
- return OSAtomicCompareAndSwap64Barrier(old_value, new_value, const_cast<int64_t*>(addr)) == 0;
-}
-
-static inline int64_t QuasiAtomicSwap64Impl(int64_t value, volatile int64_t* addr) {
- int64_t old_value;
- do {
- old_value = *addr;
- } while (QuasiAtomicCas64(old_value, value, addr));
- return old_value;
-}
-
-int64_t QuasiAtomicSwap64(int64_t value, volatile int64_t* addr) {
- return QuasiAtomicSwap64Impl(value, addr);
-}
-
-int64_t QuasiAtomicSwap64Sync(int64_t value, volatile int64_t* addr) {
- ANDROID_MEMBAR_STORE();
- int64_t old_value = QuasiAtomicSwap64Impl(value, addr);
- /* TUNING: barriers can be avoided on some architectures */
- ANDROID_MEMBAR_FULL();
- return old_value;
-}
-
-int64_t QuasiAtomicRead64(volatile const int64_t* addr) {
- return OSAtomicAdd64Barrier(0, const_cast<volatile int64_t*>(addr));
-}
-#endif
+#define NEED_MAC_QUASI_ATOMICS 1
#elif defined(__i386__) || defined(__x86_64__)
-#define NEED_QUASIATOMICS 1
+#define NEED_PTHREADS_QUASI_ATOMICS 1
-#elif __arm__
-#include <machine/cpu-features.h>
+#elif defined(__mips__)
+#define NEED_PTHREADS_QUASI_ATOMICS 1
-#ifdef __ARM_HAVE_LDREXD
+#elif defined(__arm__)
+
+#if defined(__ARM_HAVE_LDREXD)
+#define NEED_ARM_LDREXD_QUASI_ATOMICS 1
+#else
+#define NEED_PTHREADS_QUASI_ATOMICS 1
+#endif
+
+#elif defined(__sh__)
+#define NEED_PTHREADS_QUASI_ATOMICS 1
+
+#else
+#error "QuasiAtomic unsupported on this platform"
+#endif
+
+// *****************************************************************************
+
+#if NEED_ARM_LDREXD_QUASI_ATOMICS
+
static inline int64_t QuasiAtomicSwap64Impl(int64_t new_value, volatile int64_t* addr) {
int64_t prev;
int status;
do {
- __asm__ __volatile__("@ QuasiAtomicSwap64\n"
+ __asm__ __volatile__("@ QuasiAtomic::Swap64\n"
"ldrexd %0, %H0, [%3]\n"
"strexd %1, %4, %H4, [%3]"
: "=&r" (prev), "=&r" (status), "+m"(*addr)
@@ -92,22 +73,31 @@
return prev;
}
-int64_t QuasiAtomicSwap64(int64_t new_value, volatile int64_t* addr) {
+int64_t QuasiAtomic::Swap64(int64_t new_value, volatile int64_t* addr) {
return QuasiAtomicSwap64Impl(new_value, addr);
}
-int64_t QuasiAtomicSwap64Sync(int64_t new_value, volatile int64_t* addr) {
+int64_t QuasiAtomic::Swap64Sync(int64_t new_value, volatile int64_t* addr) {
ANDROID_MEMBAR_STORE();
int64_t old_value = QuasiAtomicSwap64Impl(new_value, addr);
ANDROID_MEMBAR_FULL();
return old_value;
}
-int QuasiAtomicCas64(int64_t old_value, int64_t new_value, volatile int64_t* addr) {
+int64_t QuasiAtomic::Read64(volatile const int64_t* addr) {
+ int64_t value;
+ __asm__ __volatile__("@ QuasiAtomic::Read64\n"
+ "ldrexd %0, %H0, [%1]"
+ : "=&r" (value)
+ : "r" (addr));
+ return value;
+}
+
+int QuasiAtomic::Cas64(int64_t old_value, int64_t new_value, volatile int64_t* addr) {
int64_t prev;
int status;
do {
- __asm__ __volatile__("@ QuasiAtomicCas64\n"
+ __asm__ __volatile__("@ QuasiAtomic::Cas64\n"
"ldrexd %0, %H0, [%3]\n"
"mov %1, #0\n"
"teq %0, %4\n"
@@ -120,180 +110,101 @@
return prev != old_value;
}
-int64_t QuasiAtomicRead64(volatile const int64_t* addr) {
- int64_t value;
- __asm__ __volatile__("@ QuasiAtomicRead64\n"
- "ldrexd %0, %H0, [%1]"
- : "=&r" (value)
- : "r" (addr));
- return value;
-}
+#endif
-#else
+// *****************************************************************************
-// on the device, we implement the 64-bit atomic operations through
-// mutex locking. normally, this is bad because we must initialize
-// a pthread_mutex_t before being able to use it, and this means
-// having to do an initialization check on each function call, and
-// that's where really ugly things begin...
-//
-// BUT, as a special twist, we take advantage of the fact that in our
-// pthread library, a mutex is simply a volatile word whose value is always
-// initialized to 0. In other words, simply declaring a static mutex
-// object initializes it !
-//
-// another twist is that we use a small array of mutexes to dispatch
-// the contention locks from different memory addresses
-//
+#if NEED_MAC_QUASI_ATOMICS
-#include <pthread.h>
-
-#define SWAP_LOCK_COUNT 32U
-static pthread_mutex_t _swap_locks[SWAP_LOCK_COUNT];
-
-#define SWAP_LOCK(addr) &_swap_locks[((unsigned)(void*)(addr) >> 3U) % SWAP_LOCK_COUNT]
-
-int64_t QuasiAtomicSwap64(int64_t value, volatile int64_t* addr) {
- pthread_mutex_t* lock = SWAP_LOCK(addr);
-
- pthread_mutex_lock(lock);
-
- int64_t old_value = *addr;
- *addr = value;
-
- pthread_mutex_unlock(lock);
+static inline int64_t QuasiAtomicSwap64Impl(int64_t value, volatile int64_t* addr) {
+ int64_t old_value;
+ do {
+ old_value = *addr;
+ } while (QuasiAtomic::Cas64(old_value, value, addr));
return old_value;
}
-int64_t QuasiAtomicSwap64Sync(int64_t value, volatile int64_t* addr) {
- // Same as QuasiAtomicSwap64 - mutex handles barrier.
- return QuasiAtomicSwap64(value, addr);
+int64_t QuasiAtomic::Swap64(int64_t value, volatile int64_t* addr) {
+ return QuasiAtomicSwap64Impl(value, addr);
}
-int QuasiAtomicCas64(int64_t old_value, int64_t new_value, volatile int64_t* addr) {
- int result;
- pthread_mutex_t* lock = SWAP_LOCK(addr);
+int64_t QuasiAtomic::Swap64Sync(int64_t value, volatile int64_t* addr) {
+ ANDROID_MEMBAR_STORE();
+ int64_t old_value = QuasiAtomicSwap64Impl(value, addr);
+ // TUNING: barriers can be avoided on some architectures.
+ ANDROID_MEMBAR_FULL();
+ return old_value;
+}
- pthread_mutex_lock(lock);
+int64_t QuasiAtomic::Read64(volatile const int64_t* addr) {
+ return OSAtomicAdd64Barrier(0, const_cast<volatile int64_t*>(addr));
+}
+int QuasiAtomic::Cas64(int64_t old_value, int64_t new_value, volatile int64_t* addr) {
+ return OSAtomicCompareAndSwap64Barrier(old_value, new_value, const_cast<int64_t*>(addr)) == 0;
+}
+
+#endif
+
+// *****************************************************************************
+
+#if NEED_PTHREADS_QUASI_ATOMICS
+
+// In the absence of a better implementation, we implement the 64-bit atomic
+// operations through mutex locking.
+
+// We stripe across a bunch of different mutexes to reduce contention.
+static const size_t kSwapLockCount = 32;
+static std::vector<Mutex*>* gSwapLocks;
+
+void QuasiAtomic::Startup() {
+ gSwapLocks = new std::vector<Mutex*>;
+ for (size_t i = 0; i < kSwapLockCount; ++i) {
+ gSwapLocks->push_back(new Mutex(StringPrintf("QuasiAtomic stripe %d", i).c_str()));
+ }
+}
+
+void QuasiAtomic::Shutdown() {
+ STLDeleteElements(gSwapLocks);
+ delete gSwapLocks;
+}
+
+static inline Mutex& GetSwapLock(const volatile int64_t* addr) {
+ return *(*gSwapLocks)[((unsigned)(void*)(addr) >> 3U) % kSwapLockCount];
+}
+
+int64_t QuasiAtomic::Swap64(int64_t value, volatile int64_t* addr) {
+ MutexLock mu(GetSwapLock(addr));
+ int64_t old_value = *addr;
+ *addr = value;
+ return old_value;
+}
+
+int64_t QuasiAtomic::Swap64Sync(int64_t value, volatile int64_t* addr) {
+ // Same as QuasiAtomicSwap64 - mutex handles barrier.
+ return QuasiAtomic::Swap64(value, addr);
+}
+
+int QuasiAtomic::Cas64(int64_t old_value, int64_t new_value, volatile int64_t* addr) {
+ MutexLock mu(GetSwapLock(addr));
if (*addr == old_value) {
*addr = new_value;
- result = 0;
- } else {
- result = 1;
+ return 0;
}
- pthread_mutex_unlock(lock);
- return result;
+ return 1;
}
-int64_t QuasiAtomicRead64(volatile const int64_t* addr) {
- int64_t result;
- pthread_mutex_t* lock = SWAP_LOCK(addr);
-
- pthread_mutex_lock(lock);
- result = *addr;
- pthread_mutex_unlock(lock);
- return result;
+int64_t QuasiAtomic::Read64(volatile const int64_t* addr) {
+ MutexLock mu(GetSwapLock(addr));
+ return *addr;
}
-#endif /*__ARM_HAVE_LDREXD*/
-
-/*****************************************************************************/
-#elif __sh__
-#define NEED_QUASIATOMICS 1
-
#else
-#error "Unsupported atomic operations for this platform"
+
+// The other implementations don't need any special setup.
+void QuasiAtomic::Startup() {}
+void QuasiAtomic::Shutdown() {}
+
#endif
-
-#if NEED_QUASIATOMICS
-
-/* Note that a spinlock is *not* a good idea in general
- * since they can introduce subtle issues. For example,
- * a real-time thread trying to acquire a spinlock already
- * acquired by another thread will never yeld, making the
- * CPU loop endlessly!
- *
- * However, this code is only used on the Linux simulator
- * so it's probably ok for us.
- *
- * The alternative is to use a pthread mutex, but
- * these must be initialized before being used, and
- * then you have the problem of lazily initializing
- * a mutex without any other synchronization primitive.
- *
- * TODO: these currently use sched_yield(), which is not guaranteed to
- * do anything at all. We need to use dvmIterativeSleep or a wait /
- * notify mechanism if the initial attempt fails.
- */
-
-/* global spinlock for all 64-bit quasiatomic operations */
-static int32_t quasiatomic_spinlock = 0;
-
-int QuasiAtomicCas64(int64_t old_value, int64_t new_value, volatile int64_t* addr) {
- int result;
-
- while (android_atomic_acquire_cas(0, 1, &quasiatomic_spinlock)) {
-#ifdef HAVE_WIN32_THREADS
- Sleep(0);
-#else
- sched_yield();
-#endif
- }
-
- if (*addr == old_value) {
- *addr = new_value;
- result = 0;
- } else {
- result = 1;
- }
-
- android_atomic_release_store(0, &quasiatomic_spinlock);
-
- return result;
-}
-
-int64_t QuasiAtomicRead64(volatile const int64_t* addr) {
- int64_t result;
-
- while (android_atomic_acquire_cas(0, 1, &quasiatomic_spinlock)) {
-#ifdef HAVE_WIN32_THREADS
- Sleep(0);
-#else
- sched_yield();
-#endif
- }
-
- result = *addr;
- android_atomic_release_store(0, &quasiatomic_spinlock);
-
- return result;
-}
-
-int64_t QuasiAtomicSwap64(int64_t value, volatile int64_t* addr) {
- int64_t result;
-
- while (android_atomic_acquire_cas(0, 1, &quasiatomic_spinlock)) {
-#ifdef HAVE_WIN32_THREADS
- Sleep(0);
-#else
- sched_yield();
-#endif
- }
-
- result = *addr;
- *addr = value;
- android_atomic_release_store(0, &quasiatomic_spinlock);
-
- return result;
-}
-
-int64_t QuasiAtomicSwap64Sync(int64_t value, volatile int64_t* addr) {
- // Same as QuasiAtomicSwap64 - syscall handles barrier.
- return QuasiAtomicSwap64(value, addr);
-}
-
-#endif /*NEED_QUASIATOMICS*/
-
} // namespace art
diff --git a/src/atomic.h b/src/atomic.h
index dab625e..c6c0f7d 100644
--- a/src/atomic.h
+++ b/src/atomic.h
@@ -17,44 +17,46 @@
#ifndef ART_SRC_ATOMIC_H_
#define ART_SRC_ATOMIC_H_
-#include <cutils/atomic.h> /* use common Android atomic ops */
-#include <cutils/atomic-inline.h> /* and some uncommon ones */
+#include <stdint.h>
+
+#include "cutils/atomic.h"
+#include "cutils/atomic-inline.h"
+#include "macros.h"
namespace art {
-/*
- * NOTE: Two "quasiatomic" operations on the exact same memory address
- * are guaranteed to operate atomically with respect to each other,
- * but no guarantees are made about quasiatomic operations mixed with
- * non-quasiatomic operations on the same address, nor about
- * quasiatomic operations that are performed on partially-overlapping
- * memory.
- *
- * Only the "Sync" functions provide a memory barrier.
- */
+// NOTE: Two "quasiatomic" operations on the exact same memory address
+// are guaranteed to operate atomically with respect to each other,
+// but no guarantees are made about quasiatomic operations mixed with
+// non-quasiatomic operations on the same address, nor about
+// quasiatomic operations that are performed on partially-overlapping
+// memory.
+//
+// Only the "Sync" functions provide a memory barrier.
+class QuasiAtomic {
+ public:
+ static void Startup();
-/*
- * Swap the 64-bit value at "addr" with "value". Returns the previous
- * value. No memory barriers.
- */
-int64_t QuasiAtomicSwap64(int64_t value, volatile int64_t* addr);
+ static void Shutdown();
-/*
- * Swap the 64-bit value at "addr" with "value". Returns the previous
- * value. Provides memory barriers.
- */
-int64_t QuasiAtomicSwap64Sync(int64_t value, volatile int64_t* addr);
+ // Swaps the 64-bit value at "addr" with "value". Returns the previous
+ // value. No memory barriers.
+ static int64_t Swap64(int64_t value, volatile int64_t* addr);
-/*
- * Read the 64-bit value at "addr".
- */
-int64_t QuasiAtomicRead64(volatile const int64_t* addr);
+ // Swaps the 64-bit value at "addr" with "value". Returns the previous
+ // value. Provides memory barriers.
+ static int64_t Swap64Sync(int64_t value, volatile int64_t* addr);
-/*
- * If the value at "addr" is equal to "old_value", replace it with "new_value"
- * and return 0. Otherwise, don't swap, and return nonzero.
- */
-int QuasiAtomicCas64(int64_t old_value, int64_t new_value, volatile int64_t* addr);
+ // Reads the 64-bit value at "addr".
+ static int64_t Read64(volatile const int64_t* addr);
+
+ // If the value at "addr" is equal to "old_value", replace it with "new_value"
+ // and return 0. Otherwise, don't swap, and return nonzero.
+ static int Cas64(int64_t old_value, int64_t new_value, volatile int64_t* addr);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(QuasiAtomic);
+};
} // namespace art
diff --git a/src/compiled_method.cc b/src/compiled_method.cc
index 2340cbd..980fdc9 100644
--- a/src/compiled_method.cc
+++ b/src/compiled_method.cc
@@ -134,10 +134,12 @@
case kArm:
case kThumb2:
return RoundUp(offset, kArmAlignment);
+ case kMips:
+ return RoundUp(offset, kMipsAlignment);
case kX86:
return RoundUp(offset, kX86Alignment);
default:
- LOG(FATAL) << "Unknown InstructionSet: " << static_cast<int>(instruction_set);
+ LOG(FATAL) << "Unknown InstructionSet: " << instruction_set;
return 0;
}
}
@@ -145,6 +147,7 @@
size_t CompiledMethod::CodeDelta() const {
switch (instruction_set_) {
case kArm:
+ case kMips:
case kX86:
return 0;
case kThumb2: {
@@ -152,7 +155,7 @@
return 1;
}
default:
- LOG(FATAL) << "Unknown InstructionSet: " << static_cast<int>(instruction_set_);
+ LOG(FATAL) << "Unknown InstructionSet: " << instruction_set_;
return 0;
}
}
@@ -161,6 +164,7 @@
InstructionSet instruction_set) {
switch (instruction_set) {
case kArm:
+ case kMips:
case kX86:
return code_pointer;
case kThumb2: {
@@ -170,7 +174,7 @@
return reinterpret_cast<const void*>(address);
}
default:
- LOG(FATAL) << "Unknown InstructionSet: " << static_cast<int>(instruction_set);
+ LOG(FATAL) << "Unknown InstructionSet: " << instruction_set;
return NULL;
}
}
diff --git a/src/compiler/codegen/mips/Mips32/Factory.cc b/src/compiler/codegen/mips/Mips32/Factory.cc
index 1162702..649aed3 100644
--- a/src/compiler/codegen/mips/Mips32/Factory.cc
+++ b/src/compiler/codegen/mips/Mips32/Factory.cc
@@ -434,7 +434,6 @@
int rIndex, int rSrc, int scale, OpSize size)
{
LIR *first = NULL;
- LIR *res;
MipsOpCode opcode = kMipsNop;
int rNewIndex = rIndex;
int tReg = oatAllocTemp(cUnit);
@@ -477,7 +476,7 @@
default:
LOG(FATAL) << "Bad case in storeBaseIndexed";
}
- res = newLIR3(cUnit, opcode, rSrc, 0, tReg);
+ newLIR3(cUnit, opcode, rSrc, 0, tReg);
oatFreeTemp(cUnit, rNewIndex);
return first;
}
diff --git a/src/compiler/codegen/x86/Assemble.cc b/src/compiler/codegen/x86/Assemble.cc
index d9cdabf..3a86bed 100644
--- a/src/compiler/codegen/x86/Assemble.cc
+++ b/src/compiler/codegen/x86/Assemble.cc
@@ -134,9 +134,9 @@
{ kX86Imul16RMI, kRegMemImm, IS_LOAD | IS_QUAD_OP | SETS_CCODES, { 0x66, 0, 0x69, 0, 0, 0, 0, 2 }, "Imul16RMI", "!0r,[!1r+!2d],!3d" },
{ kX86Imul16RAI, kRegArrayImm, IS_LOAD | IS_SEXTUPLE_OP | SETS_CCODES, { 0x66, 0, 0x69, 0, 0, 0, 0, 2 }, "Imul16RAI", "!0r,[!1r+!2r<<!3d+!4d],!5d" },
- { kX86Imul32RRI, kRegRegImm, IS_TERTIARY_OP | SETS_CCODES, { 0, 0, 0x69, 0, 0, 0, 0, 2 }, "Imul32RRI", "!0r,!1r,!2d" },
- { kX86Imul32RMI, kRegMemImm, IS_LOAD | IS_QUAD_OP | SETS_CCODES, { 0, 0, 0x69, 0, 0, 0, 0, 2 }, "Imul32RMI", "!0r,[!1r+!2d],!3d" },
- { kX86Imul32RAI, kRegArrayImm, IS_LOAD | IS_SEXTUPLE_OP | SETS_CCODES, { 0, 0, 0x69, 0, 0, 0, 0, 2 }, "Imul32RAI", "!0r,[!1r+!2r<<!3d+!4d],!5d" },
+ { kX86Imul32RRI, kRegRegImm, IS_TERTIARY_OP | SETS_CCODES, { 0, 0, 0x69, 0, 0, 0, 0, 4 }, "Imul32RRI", "!0r,!1r,!2d" },
+ { kX86Imul32RMI, kRegMemImm, IS_LOAD | IS_QUAD_OP | SETS_CCODES, { 0, 0, 0x69, 0, 0, 0, 0, 4 }, "Imul32RMI", "!0r,[!1r+!2d],!3d" },
+ { kX86Imul32RAI, kRegArrayImm, IS_LOAD | IS_SEXTUPLE_OP | SETS_CCODES, { 0, 0, 0x69, 0, 0, 0, 0, 4 }, "Imul32RAI", "!0r,[!1r+!2r<<!3d+!4d],!5d" },
{ kX86Imul32RRI8, kRegRegImm, IS_TERTIARY_OP | SETS_CCODES, { 0, 0, 0x6B, 0, 0, 0, 0, 1 }, "Imul32RRI8", "!0r,!1r,!2d" },
{ kX86Imul32RMI8, kRegMemImm, IS_LOAD | IS_QUAD_OP | SETS_CCODES, { 0, 0, 0x6B, 0, 0, 0, 0, 1 }, "Imul32RMI8", "!0r,[!1r+!2d],!3d" },
{ kX86Imul32RAI8, kRegArrayImm, IS_LOAD | IS_SEXTUPLE_OP | SETS_CCODES, { 0, 0, 0x6B, 0, 0, 0, 0, 1 }, "Imul32RAI8", "!0r,[!1r+!2r<<!3d+!4d],!5d" },
diff --git a/src/compiler/codegen/x86/X86/Factory.cc b/src/compiler/codegen/x86/X86/Factory.cc
index 2bd5b42..8e991a0 100644
--- a/src/compiler/codegen/x86/X86/Factory.cc
+++ b/src/compiler/codegen/x86/X86/Factory.cc
@@ -567,15 +567,12 @@
int rSrc, int rSrcHi,
OpSize size, int sReg) {
LIR *store = NULL;
- LIR *store2 = NULL;
bool isArray = rIndex != INVALID_REG;
bool pair = false;
- bool is64bit = false;
X86OpCode opcode = kX86Nop;
switch (size) {
case kLong:
case kDouble:
- is64bit = true;
if (FPREG(rSrc)) {
opcode = isArray ? kX86MovsdAR : kX86MovsdMR;
if (DOUBLEREG(rSrc)) {
@@ -619,14 +616,14 @@
store = newLIR3(cUnit, opcode, rBase, displacement + LOWORD_OFFSET, rSrc);
} else {
store = newLIR3(cUnit, opcode, rBase, displacement + LOWORD_OFFSET, rSrc);
- store2 = newLIR3(cUnit, opcode, rBase, displacement + HIWORD_OFFSET, rSrcHi);
+ newLIR3(cUnit, opcode, rBase, displacement + HIWORD_OFFSET, rSrcHi);
}
} else {
if (!pair) {
store = newLIR5(cUnit, opcode, rBase, rIndex, scale, displacement + LOWORD_OFFSET, rSrc);
} else {
store = newLIR5(cUnit, opcode, rBase, rIndex, scale, displacement + LOWORD_OFFSET, rSrc);
- store2 = newLIR5(cUnit, opcode, rBase, rIndex, scale, displacement + HIWORD_OFFSET, rSrcHi);
+ newLIR5(cUnit, opcode, rBase, rIndex, scale, displacement + HIWORD_OFFSET, rSrcHi);
}
}
diff --git a/src/compiler_llvm/compilation_unit.h b/src/compiler_llvm/compilation_unit.h
index 2f98521..fb5f4e4 100644
--- a/src/compiler_llvm/compilation_unit.h
+++ b/src/compiler_llvm/compilation_unit.h
@@ -98,7 +98,7 @@
bool IsMaterializeThresholdReached() const {
MutexLock GUARD(cunit_lock_);
- return (mem_usage_ > 100000000u); // (threshold: 100 MB)
+ return (mem_usage_ > 10000000u); // (threshold: 10 MB)
}
void AddMemUsageApproximation(size_t usage) {
diff --git a/src/compiler_llvm/frontend.cc b/src/compiler_llvm/frontend.cc
deleted file mode 100644
index 7507b26..0000000
--- a/src/compiler_llvm/frontend.cc
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2012 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.
- */
-
-#include "dex_file.h"
-#include "logging.h"
-
-#include <stdint.h>
-
-namespace art {
-
-int oatVRegOffset(const DexFile::CodeItem* code_item,
- uint32_t core_spills, uint32_t fp_spills,
- size_t frame_size, int reg) {
-
- // TODO: Remove oatVRegOffset() after we have adapted the OatWriter
- // and OatFile.
-
- UNIMPLEMENTED(WARNING) << "oatVRegOffset() is not and won't be "
- << "implemented in LLVM backend";
- return 0;
-}
-
-} // namespace art
diff --git a/src/compiler_llvm/jni_compiler.cc b/src/compiler_llvm/jni_compiler.cc
index 02985f7..5a8cc46 100644
--- a/src/compiler_llvm/jni_compiler.cc
+++ b/src/compiler_llvm/jni_compiler.cc
@@ -112,11 +112,6 @@
llvm::StructType* shadow_frame_type = irb_.getShadowFrameTy(sirt_size);
llvm::AllocaInst* shadow_frame_ = irb_.CreateAlloca(shadow_frame_type);
- // Zero-initialization of the shadow frame
- llvm::ConstantAggregateZero* zero_initializer =
- llvm::ConstantAggregateZero::get(shadow_frame_type);
- irb_.CreateStore(zero_initializer, shadow_frame_);
-
// Store the method pointer
llvm::Value* method_field_addr =
irb_.CreatePtrDisp(shadow_frame_,
diff --git a/src/compiler_llvm/method_compiler.cc b/src/compiler_llvm/method_compiler.cc
index 8d6b251..f9a2833 100644
--- a/src/compiler_llvm/method_compiler.cc
+++ b/src/compiler_llvm/method_compiler.cc
@@ -36,12 +36,9 @@
#include <iomanip>
#include <llvm/BasicBlock.h>
-#include <llvm/DerivedTypes.h>
#include <llvm/Function.h>
#include <llvm/GlobalVariable.h>
#include <llvm/Intrinsics.h>
-#include <llvm/Module.h>
-#include <llvm/Type.h>
namespace art {
namespace compiler_llvm {
@@ -66,7 +63,7 @@
irb_(*cunit->GetIRBuilder()), func_(NULL), retval_reg_(NULL),
basic_block_stack_overflow_(NULL),
basic_block_reg_alloca_(NULL), basic_block_shadow_frame_alloca_(NULL),
- basic_block_reg_zero_init_(NULL), basic_block_reg_arg_init_(NULL),
+ basic_block_reg_arg_init_(NULL),
basic_blocks_(code_item_->insns_size_in_code_units_),
basic_block_landing_pads_(code_item_->tries_size_, NULL),
basic_block_unwind_(NULL), basic_block_unreachable_(NULL),
@@ -151,9 +148,6 @@
basic_block_shadow_frame_alloca_ =
llvm::BasicBlock::Create(*context_, "prologue.shadowframe", func_);
- basic_block_reg_zero_init_ =
- llvm::BasicBlock::Create(*context_, "prologue.zeroinit", func_);
-
basic_block_reg_arg_init_ =
llvm::BasicBlock::Create(*context_, "prologue.arginit", func_);
@@ -238,9 +232,6 @@
irb_.CreateBr(basic_block_shadow_frame_alloca_);
irb_.SetInsertPoint(basic_block_shadow_frame_alloca_);
- irb_.CreateBr(basic_block_reg_zero_init_);
-
- irb_.SetInsertPoint(basic_block_reg_zero_init_);
irb_.CreateBr(basic_block_reg_arg_init_);
}
@@ -2131,15 +2122,13 @@
EmitGuard_GarbageCollectionSuspend(dex_pc);
}
- if (src1_reg_cat == kRegZero && src2_reg_cat == kRegZero) {
- irb_.CreateBr(GetBasicBlock(dex_pc + branch_offset));
- return;
- }
-
llvm::Value* src1_value;
llvm::Value* src2_value;
- if (src1_reg_cat != kRegZero && src2_reg_cat != kRegZero) {
+ if (src1_reg_cat == kRegZero && src2_reg_cat == kRegZero) {
+ src1_value = irb_.getInt32(0);
+ src2_value = irb_.getInt32(0);
+ } else if (src1_reg_cat != kRegZero && src2_reg_cat != kRegZero) {
CHECK_EQ(src1_reg_cat, src2_reg_cat);
if (src1_reg_cat == kRegCat1nr) {
@@ -2199,15 +2188,13 @@
EmitGuard_GarbageCollectionSuspend(dex_pc);
}
- if (src_reg_cat == kRegZero) {
- irb_.CreateBr(GetBasicBlock(dex_pc + branch_offset));
- return;
- }
-
llvm::Value* src1_value;
llvm::Value* src2_value;
- if (src_reg_cat == kRegCat1nr) {
+ if (src_reg_cat == kRegZero) {
+ src1_value = irb_.getInt32(0);
+ src2_value = irb_.getInt32(0);
+ } else if (src_reg_cat == kRegCat1nr) {
src1_value = EmitLoadDalvikReg(dec_insn.vA, kInt, kAccurate);
src2_value = irb_.getInt32(0);
} else {
@@ -2840,8 +2827,8 @@
if (direct_method != 0u &&
direct_method != static_cast<uintptr_t>(-1)) {
callee_method_object_addr =
- EmitLoadSDCalleeDirectMethodObjectAddr(callee_method_idx,
- direct_method);
+ irb_.CreateIntToPtr(irb_.getPtrEquivInt(direct_method),
+ irb_.getJObjectTy());
} else {
callee_method_object_addr =
EmitLoadSDCalleeMethodObjectAddr(callee_method_idx);
@@ -2992,27 +2979,6 @@
llvm::Value* MethodCompiler::
-EmitLoadSDCalleeDirectMethodObjectAddr(uint32_t callee_method_idx,
- uintptr_t direct_method) {
- std::string direct_method_name(
- StringPrintf("ArtMethodObject_%08lx",
- static_cast<unsigned long>(direct_method)));
-
- llvm::GlobalVariable* direct_method_addr =
- module_->getGlobalVariable(direct_method_name);
-
- if (direct_method_addr == NULL) {
- direct_method_addr =
- new llvm::GlobalVariable(*module_, irb_.getJObjectTy()->getElementType(),
- false, llvm::GlobalVariable::ExternalLinkage,
- NULL, direct_method_name);
- }
-
- return direct_method_addr;
-}
-
-
-llvm::Value* MethodCompiler::
EmitLoadSDCalleeMethodObjectAddr(uint32_t callee_method_idx) {
llvm::Value* callee_method_object_field_addr =
EmitLoadDexCacheResolvedMethodFieldAddr(callee_method_idx);
@@ -3875,16 +3841,11 @@
// Find catch block with matching type
llvm::Value* method_object_addr = EmitLoadMethodObjectAddr();
- // TODO: Maybe passing try item offset will be a better idea? For now,
- // we are passing dex_pc, so that we can use existing runtime support
- // function directly. However, in the runtime supporting function we
- // have to search for try item with binary search which can be
- // eliminated.
- llvm::Value* dex_pc_value = irb_.getInt32(ti->start_addr_);
+ llvm::Value* ti_offset_value = irb_.getInt32(ti_offset);
llvm::Value* catch_handler_index_value =
irb_.CreateCall2(irb_.GetRuntime(FindCatchBlock),
- method_object_addr, dex_pc_value);
+ method_object_addr, ti_offset_value);
// Switch instruction (Go to unwind basic block by default)
llvm::SwitchInst* sw =
@@ -3954,18 +3915,12 @@
irb_.SetInsertPoint(basic_block_reg_alloca_);
reg_addr = irb_.CreateAlloca(irb_.getJIntTy(), 0,
StringPrintf("r%u", reg_idx));
-
- irb_.SetInsertPoint(basic_block_reg_zero_init_);
- irb_.CreateStore(irb_.getJInt(0), reg_addr);
break;
case kRegCat2:
irb_.SetInsertPoint(basic_block_reg_alloca_);
reg_addr = irb_.CreateAlloca(irb_.getJLongTy(), 0,
StringPrintf("w%u", reg_idx));
-
- irb_.SetInsertPoint(basic_block_reg_zero_init_);
- irb_.CreateStore(irb_.getJLong(0), reg_addr);
break;
case kRegObject:
@@ -3980,9 +3935,6 @@
reg_addr = irb_.CreateGEP(shadow_frame_, gep_index,
StringPrintf("p%u", reg_idx));
-
- irb_.SetInsertPoint(basic_block_reg_zero_init_);
- irb_.CreateStore(irb_.getJNull(), reg_addr);
}
break;
diff --git a/src/compiler_llvm/method_compiler.h b/src/compiler_llvm/method_compiler.h
index 84c55d6..d5a4374 100644
--- a/src/compiler_llvm/method_compiler.h
+++ b/src/compiler_llvm/method_compiler.h
@@ -215,9 +215,6 @@
llvm::Value* EmitLoadSDCalleeMethodObjectAddr(uint32_t callee_method_idx);
- llvm::Value* EmitLoadSDCalleeDirectMethodObjectAddr(uint32_t callee_method_idx,
- uintptr_t direct_method);
-
llvm::Value* EmitLoadVirtualCalleeMethodObjectAddr(int vtable_idx,
llvm::Value* this_addr);
@@ -459,7 +456,6 @@
llvm::BasicBlock* basic_block_stack_overflow_;
llvm::BasicBlock* basic_block_reg_alloca_;
llvm::BasicBlock* basic_block_shadow_frame_alloca_;
- llvm::BasicBlock* basic_block_reg_zero_init_;
llvm::BasicBlock* basic_block_reg_arg_init_;
std::vector<llvm::BasicBlock*> basic_blocks_;
diff --git a/src/compiler_llvm/runtime_support_llvm.cc b/src/compiler_llvm/runtime_support_llvm.cc
index 1ebbef9..bdfd222 100644
--- a/src/compiler_llvm/runtime_support_llvm.cc
+++ b/src/compiler_llvm/runtime_support_llvm.cc
@@ -159,14 +159,18 @@
ThrowVerificationError(art_get_current_thread_from_code(), current_method, kind, ref);
}
-int32_t art_find_catch_block_from_code(Method* current_method, int32_t dex_pc) {
+int32_t art_find_catch_block_from_code(Method* current_method,
+ uint32_t ti_offset) {
Thread* thread = art_get_current_thread_from_code();
Class* exception_type = thread->GetException()->GetClass();
MethodHelper mh(current_method);
const DexFile::CodeItem* code_item = mh.GetCodeItem();
+ DCHECK_LT(ti_offset, code_item->tries_size_);
+ const DexFile::TryItem* try_item = DexFile::GetTryItems(*code_item, ti_offset);
+
int iter_index = 0;
// Iterate over the catch handlers associated with dex_pc
- for (CatchHandlerIterator it(*code_item, dex_pc); it.HasNext(); it.Next()) {
+ for (CatchHandlerIterator it(*code_item, *try_item); it.HasNext(); it.Next()) {
uint16_t iter_type_idx = it.GetHandlerTypeIndex();
// Catch all case
if (iter_type_idx == DexFile::kDexNoIndex16) {
@@ -509,8 +513,8 @@
Thread* thread = art_get_current_thread_from_code();
thread->ThrowNewExceptionF("Ljava/lang/ClassCastException;",
"%s cannot be cast to %s",
- PrettyDescriptor(dest_type).c_str(),
- PrettyDescriptor(src_type).c_str());
+ PrettyDescriptor(src_type).c_str(),
+ PrettyDescriptor(dest_type).c_str());
}
}
@@ -797,15 +801,6 @@
}
}
- // Fixed method object address
- const char method_object_prefix[] = "ArtMethodObject_";
- const size_t method_object_prefix_len = sizeof(method_object_prefix) - 1;
- if (strncmp(name, method_object_prefix, method_object_prefix_len) == 0) {
- const char* addr_str = name + method_object_prefix_len;
- unsigned long addr_int = strtoul(addr_str, NULL, 16);
- return reinterpret_cast<void*>(addr_int);
- }
-
LOG(FATAL) << "Error: Can't find symbol " << name;
return 0;
}
diff --git a/src/compiler_llvm/runtime_support_llvm.h b/src/compiler_llvm/runtime_support_llvm.h
index 6e3b81c..f8228c5 100644
--- a/src/compiler_llvm/runtime_support_llvm.h
+++ b/src/compiler_llvm/runtime_support_llvm.h
@@ -59,7 +59,8 @@
void art_throw_exception_from_code(Object* exception);
-int32_t art_find_catch_block_from_code(Method* current_method, int32_t dex_pc);
+int32_t art_find_catch_block_from_code(Method* current_method,
+ uint32_t ti_offset);
void art_test_suspend_from_code(Thread* thread);
diff --git a/src/dex_file.cc b/src/dex_file.cc
index 85dafee..eb2a157 100644
--- a/src/dex_file.cc
+++ b/src/dex_file.cc
@@ -1001,9 +1001,19 @@
default:
offset = DexFile::FindCatchHandlerOffset(code_item, code_item.tries_size_, address);
}
+ Init(code_item, offset);
+}
+
+CatchHandlerIterator::CatchHandlerIterator(const DexFile::CodeItem& code_item,
+ const DexFile::TryItem& try_item) {
+ handler_.address_ = -1;
+ Init(code_item, try_item.handler_off_);
+}
+
+void CatchHandlerIterator::Init(const DexFile::CodeItem& code_item,
+ int32_t offset) {
if (offset >= 0) {
- const byte* handler_data = DexFile::GetCatchHandlerData(code_item, offset);
- Init(handler_data);
+ Init(DexFile::GetCatchHandlerData(code_item, offset));
} else {
// Not found, initialize as empty
current_data_ = NULL;
diff --git a/src/dex_file.h b/src/dex_file.h
index 9c16440..aeb7e89 100644
--- a/src/dex_file.h
+++ b/src/dex_file.h
@@ -307,6 +307,15 @@
DISALLOW_COPY_AND_ASSIGN(AnnotationItem);
};
+ struct PACKED Payload {
+ uint16_t ident; // kPackedSwitchSignature, kSparseSwitchSignature, or kArrayDataSignature.
+ uint16_t element_width;
+ uint32_t element_count;
+ uint8_t data[];
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Payload);
+ };
+
typedef std::pair<const DexFile*, const DexFile::ClassDef*> ClassPathEntry;
typedef std::vector<const DexFile*> ClassPath;
@@ -1119,6 +1128,10 @@
class CatchHandlerIterator {
public:
CatchHandlerIterator(const DexFile::CodeItem& code_item, uint32_t address);
+
+ CatchHandlerIterator(const DexFile::CodeItem& code_item,
+ const DexFile::TryItem& try_item);
+
explicit CatchHandlerIterator(const byte* handler_data) {
Init(handler_data);
}
@@ -1139,6 +1152,7 @@
return current_data_;
}
private:
+ void Init(const DexFile::CodeItem& code_item, int32_t offset);
void Init(const byte* handler_data);
struct CatchHandlerItem {
diff --git a/src/dex_instruction.cc b/src/dex_instruction.cc
index e0b10f9..8744326 100644
--- a/src/dex_instruction.cc
+++ b/src/dex_instruction.cc
@@ -299,7 +299,17 @@
case k22x: os << StringPrintf("%s v%d, v%d", opcode, insn.vA, insn.vB); break;
case k21t: os << StringPrintf("%s v%d, %+d", opcode, insn.vA, insn.vB); break;
case k21s: os << StringPrintf("%s v%d, #%+d", opcode, insn.vA, insn.vB); break;
- case k21h: os << StringPrintf("%s v%d, #%+d00000[00000000]", opcode, insn.vA, insn.vB); break;
+ case k21h: {
+ // op vAA, #+BBBB0000[00000000]
+ if (insn.opcode == CONST_HIGH16) {
+ uint32_t value = insn.vB << 16;
+ os << StringPrintf("%s v%d, #int %+d // 0x%x", opcode, insn.vA, value, value);
+ } else {
+ uint64_t value = static_cast<uint64_t>(insn.vB) << 48;
+ os << StringPrintf("%s v%d, #long %+lld // 0x%llx", opcode, insn.vA, value, value);
+ }
+ }
+ break;
case k21c: os << StringPrintf("%s v%d, thing@%d", opcode, insn.vA, insn.vB); break;
case k23x: os << StringPrintf("%s v%d, v%d, v%d", opcode, insn.vA, insn.vB, insn.vC); break;
case k22b: os << StringPrintf("%s v%d, v%d, #%+d", opcode, insn.vA, insn.vB, insn.vC); break;
diff --git a/src/disassembler.cc b/src/disassembler.cc
index 3396229..8fe3dc7 100644
--- a/src/disassembler.cc
+++ b/src/disassembler.cc
@@ -19,6 +19,7 @@
#include <iostream>
#include "disassembler_arm.h"
+#include "disassembler_mips.h"
#include "disassembler_x86.h"
#include "logging.h"
@@ -27,6 +28,8 @@
Disassembler* Disassembler::Create(InstructionSet instruction_set) {
if (instruction_set == kArm || instruction_set == kThumb2) {
return new arm::DisassemblerArm();
+ } else if (instruction_set == kMips) {
+ return new mips::DisassemblerMips();
} else if (instruction_set == kX86) {
return new x86::DisassemblerX86();
} else {
diff --git a/src/disassembler_mips.cc b/src/disassembler_mips.cc
new file mode 100644
index 0000000..f7d755a
--- /dev/null
+++ b/src/disassembler_mips.cc
@@ -0,0 +1,271 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#include "disassembler_mips.h"
+
+#include <iostream>
+
+#include "logging.h"
+#include "stringprintf.h"
+#include "thread.h"
+
+namespace art {
+namespace mips {
+
+struct MipsInstruction {
+ uint32_t mask;
+ uint32_t value;
+ const char* name;
+ const char* args_fmt;
+
+ bool Matches(uint32_t instruction) const {
+ return (instruction & mask) == value;
+ }
+};
+
+static const uint32_t kOpcodeShift = 26;
+
+static const uint32_t kCop1 = (17 << kOpcodeShift);
+
+static const uint32_t kITypeMask = (0x3f << kOpcodeShift);
+static const uint32_t kJTypeMask = (0x3f << kOpcodeShift);
+static const uint32_t kRTypeMask = ((0x3f << kOpcodeShift) | (0x3f));
+static const uint32_t kSpecial2Mask = (0x3f << kOpcodeShift);
+static const uint32_t kFpMask = kRTypeMask;
+
+static const MipsInstruction gMipsInstructions[] = {
+ // "sll r0, r0, 0" is the canonical "nop", used in delay slots.
+ { 0xffffffff, 0, "nop", "" },
+
+ // R-type instructions.
+ { kRTypeMask, 0, "sll", "DTA", },
+ // 0, 1, movci
+ { kRTypeMask, 2, "srl", "DTA", },
+ { kRTypeMask, 3, "sra", "DTA", },
+ { kRTypeMask, 4, "sllv", "DTS", },
+ { kRTypeMask, 6, "srlv", "DTS", },
+ { kRTypeMask, 7, "srav", "DTS", },
+ { kRTypeMask, 8, "jr", "S", },
+ { kRTypeMask | (0x1f << 11), 9 | (31 << 11), "jalr", "S", }, // rd = 31 is implicit.
+ { kRTypeMask, 9, "jalr", "DS", }, // General case.
+ { kRTypeMask | (0x1f << 6), 10, "movz", "DST", },
+ { kRTypeMask | (0x1f << 6), 11, "movn", "DST", },
+ { kRTypeMask, 12, "syscall", "", }, // TODO: code
+ { kRTypeMask, 13, "break", "", }, // TODO: code
+ { kRTypeMask, 15, "sync", "", }, // TODO: type
+ { kRTypeMask, 16, "mfhi", "D", },
+ { kRTypeMask, 17, "mthi", "S", },
+ { kRTypeMask, 18, "mflo", "D", },
+ { kRTypeMask, 19, "mtlo", "S", },
+ { kRTypeMask, 24, "mult", "ST", },
+ { kRTypeMask, 25, "multu", "ST", },
+ { kRTypeMask, 26, "div", "ST", },
+ { kRTypeMask, 27, "divu", "ST", },
+ { kRTypeMask, 32, "add", "DST", },
+ { kRTypeMask, 33, "addu", "DST", },
+ { kRTypeMask, 34, "sub", "DST", },
+ { kRTypeMask, 35, "subu", "DST", },
+ { kRTypeMask, 36, "and", "DST", },
+ { kRTypeMask, 37, "or", "DST", },
+ { kRTypeMask, 38, "xor", "DST", },
+ { kRTypeMask, 39, "nor", "DST", },
+ { kRTypeMask, 42, "slt", "DST", },
+ { kRTypeMask, 43, "sltu", "DST", },
+ // 0, 48, tge
+ // 0, 49, tgeu
+ // 0, 50, tlt
+ // 0, 51, tltu
+ // 0, 52, teq
+ // 0, 54, tne
+
+ // SPECIAL2
+ { kSpecial2Mask | 0x7ff, (28 << kOpcodeShift) | 2, "mul", "DST" },
+ { kSpecial2Mask | 0x7ff, (28 << kOpcodeShift) | 32, "clz", "DS" },
+ { kSpecial2Mask | 0xffff, (28 << kOpcodeShift) | 0, "madd", "ST" },
+ { kSpecial2Mask | 0xffff, (28 << kOpcodeShift) | 1, "maddu", "ST" },
+ { kSpecial2Mask | 0xffff, (28 << kOpcodeShift) | 2, "mul", "DST" },
+ { kSpecial2Mask | 0xffff, (28 << kOpcodeShift) | 4, "msub", "ST" },
+ { kSpecial2Mask | 0xffff, (28 << kOpcodeShift) | 5, "msubu", "ST" },
+ { kSpecial2Mask | 0x3f, (28 << kOpcodeShift) | 0x3f, "sdbbp", "" }, // TODO: code
+
+ // J-type instructions.
+ { kJTypeMask, 2 << kOpcodeShift, "j", "L" },
+ { kJTypeMask, 3 << kOpcodeShift, "jal", "L" },
+
+ // I-type instructions.
+ { kITypeMask, 4 << kOpcodeShift, "beq", "STB" },
+ { kITypeMask, 5 << kOpcodeShift, "bne", "STB" },
+ { kITypeMask | (0x1f << 16), 1 << kOpcodeShift | (1 << 16), "bgez", "SB" },
+ { kITypeMask | (0x1f << 16), 1 << kOpcodeShift | (0 << 16), "bltz", "SB" },
+ { kITypeMask | (0x1f << 16), 1 << kOpcodeShift | (2 << 16), "bltzl", "SB" },
+ { kITypeMask | (0x1f << 16), 1 << kOpcodeShift | (16 << 16), "bltzal", "SB" },
+ { kITypeMask | (0x1f << 16), 1 << kOpcodeShift | (18 << 16), "bltzall", "SB" },
+ { kITypeMask | (0x1f << 16), 6 << kOpcodeShift | (0 << 16), "blez", "SB" },
+ { kITypeMask | (0x1f << 16), 7 << kOpcodeShift | (0 << 16), "bgtz", "SB" },
+
+ { 0xffff0000, (4 << kOpcodeShift), "b", "B" },
+ { 0xffff0000, (1 << kOpcodeShift) | (17 << 16), "bal", "B" },
+
+ { kITypeMask, 8 << kOpcodeShift, "addi", "TSi", },
+ { kITypeMask, 9 << kOpcodeShift, "addiu", "TSi", },
+ { kITypeMask, 10 << kOpcodeShift, "slti", "TSi", },
+ { kITypeMask, 11 << kOpcodeShift, "sltiu", "TSi", },
+ { kITypeMask, 12 << kOpcodeShift, "andi", "TSi", },
+ { kITypeMask, 13 << kOpcodeShift, "ori", "TSi", },
+ { kITypeMask, 14 << kOpcodeShift, "ori", "TSi", },
+ { kITypeMask, 15 << kOpcodeShift, "lui", "TI", },
+
+ { kITypeMask, 32 << kOpcodeShift, "lb", "TO", },
+ { kITypeMask, 33 << kOpcodeShift, "lh", "TO", },
+ { kITypeMask, 35 << kOpcodeShift, "lw", "TO", },
+ { kITypeMask, 36 << kOpcodeShift, "lbu", "TO", },
+ { kITypeMask, 37 << kOpcodeShift, "lhu", "TO", },
+ { kITypeMask, 40 << kOpcodeShift, "sb", "TO", },
+ { kITypeMask, 41 << kOpcodeShift, "sh", "TO", },
+ { kITypeMask, 43 << kOpcodeShift, "sw", "TO", },
+ { kITypeMask, 49 << kOpcodeShift, "lwc1", "tO", },
+ { kITypeMask, 57 << kOpcodeShift, "swc1", "tO", },
+
+ // Floating point.
+ { kFpMask, kCop1 | 0, "add", "fdst" },
+ { kFpMask, kCop1 | 1, "sub", "fdst" },
+ { kFpMask, kCop1 | 2, "mul", "fdst" },
+ { kFpMask, kCop1 | 3, "div", "fdst" },
+ { kFpMask | (0x1f << 16), kCop1 | 4, "sqrt", "fdst" },
+ { kFpMask | (0x1f << 16), kCop1 | 5, "abs", "fds" },
+ { kFpMask | (0x1f << 16), kCop1 | 6, "mov", "fds" },
+ { kFpMask | (0x1f << 16), kCop1 | 7, "neg", "fds" },
+ { kFpMask | (0x1f << 16), kCop1 | 8, "round.l", "fds" },
+ { kFpMask | (0x1f << 16), kCop1 | 9, "trunc.l", "fds" },
+ { kFpMask | (0x1f << 16), kCop1 | 10, "ceil.l", "fds" },
+ { kFpMask | (0x1f << 16), kCop1 | 11, "floor.l", "fds" },
+ { kFpMask | (0x1f << 16), kCop1 | 12, "round.w", "fds" },
+ { kFpMask | (0x1f << 16), kCop1 | 13, "trunc.w", "fds" },
+ { kFpMask | (0x1f << 16), kCop1 | 14, "ceil.w", "fds" },
+ { kFpMask | (0x1f << 16), kCop1 | 15, "floor.w", "fds" },
+ { kFpMask | (0x1f << 16), kCop1 | 32, "cvt.s", "fds" },
+ { kFpMask | (0x1f << 16), kCop1 | 33, "cvt.d", "fds" },
+ { kFpMask | (0x1f << 16), kCop1 | 36, "cvt.w", "fds" },
+ { kFpMask | (0x1f << 16), kCop1 | 37, "cvt.l", "fds" },
+ { kFpMask | (0x1f << 16), kCop1 | 38, "cvt.ps", "fds" },
+};
+
+static uint32_t ReadU32(const uint8_t* ptr) {
+ // TODO: MIPS is bi. how do we handle that?
+ return ptr[3] | (ptr[2] << 8) | (ptr[1] << 16) | (ptr[0] << 24);
+ //return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24);
+}
+
+static void DumpMips(std::ostream& os, const uint8_t* instr_ptr) {
+ uint32_t instruction = ReadU32(instr_ptr);
+
+ uint32_t rs = (instruction >> 21) & 0x1f; // I-type, R-type.
+ uint32_t rt = (instruction >> 16) & 0x1f; // I-type, R-type.
+ uint32_t rd = (instruction >> 11) & 0x1f; // R-type.
+ uint32_t sa = (instruction >> 6) & 0x1f; // R-type.
+
+ std::string opcode;
+ std::ostringstream args;
+
+ // TODO: remove this!
+ uint32_t op = (instruction >> 26) & 0x3f;
+ uint32_t function = (instruction & 0x3f); // R-type.
+ opcode = StringPrintf("op=%d fn=%d", op, function);
+
+ for (size_t i = 0; i < arraysize(gMipsInstructions); ++i) {
+ if (gMipsInstructions[i].Matches(instruction)) {
+ opcode = gMipsInstructions[i].name;
+ for (const char* args_fmt = gMipsInstructions[i].args_fmt; *args_fmt; ++args_fmt) {
+ switch (*args_fmt) {
+ case 'A': // sa (shift amount).
+ args << sa;
+ break;
+ case 'B': // Branch offset.
+ {
+ int32_t offset = static_cast<int16_t>(instruction & 0xffff);
+ offset <<= 2;
+ offset += 4; // Delay slot.
+ args << StringPrintf("%p ; %+d", instr_ptr + offset, offset);
+ }
+ break;
+ case 'D': args << 'r' << rd; break;
+ case 'd': args << 'f' << rd; break;
+ case 'f': // Floating point "fmt".
+ {
+ size_t fmt = (instruction >> 21) & 0x7; // TODO: other fmts?
+ switch (fmt) {
+ case 0: opcode += ".s"; break;
+ case 1: opcode += ".d"; break;
+ case 4: opcode += ".w"; break;
+ case 5: opcode += ".l"; break;
+ case 6: opcode += ".ps"; break;
+ default: opcode += ".?"; break;
+ }
+ continue; // No ", ".
+ }
+ break;
+ case 'I': // Upper 16-bit immediate.
+ args << reinterpret_cast<void*>((instruction & 0xffff) << 16);
+ break;
+ case 'i': // Sign-extended lower 16-bit immediate.
+ args << static_cast<int16_t>(instruction & 0xffff);
+ break;
+ case 'L': // Jump label.
+ {
+ // TODO: is this right?
+ uint32_t instr_index = (instruction & 0x1ffffff);
+ uint32_t target = (instr_index << 2);
+ target |= (reinterpret_cast<uintptr_t>(instr_ptr + 4) & 0xf0000000);
+ args << reinterpret_cast<void*>(target);
+ }
+ break;
+ case 'O': // +x(rs)
+ {
+ int32_t offset = static_cast<int16_t>(instruction & 0xffff);
+ args << StringPrintf("%+d(r%d)", offset, rs);
+ if (rs == 17) {
+ args << " ; ";
+ Thread::DumpThreadOffset(args, offset, 4);
+ }
+ }
+ break;
+ case 'S': args << 'r' << rs; break;
+ case 's': args << 'f' << rs; break;
+ case 'T': args << 'r' << rt; break;
+ case 't': args << 'f' << rt; break;
+ }
+ if (*(args_fmt + 1)) {
+ args << ", ";
+ }
+ }
+ break;
+ }
+ }
+
+ os << StringPrintf("\t\t\t%p: %08x\t%-7s ", instr_ptr, instruction, opcode.c_str()) << args.str() << '\n';
+}
+
+DisassemblerMips::DisassemblerMips() {
+}
+
+void DisassemblerMips::Dump(std::ostream& os, const uint8_t* begin, const uint8_t* end) {
+ for (const uint8_t* cur = begin; cur < end; cur += 4) {
+ DumpMips(os, cur);
+ }
+}
+
+} // namespace mips
+} // namespace art
diff --git a/src/disassembler_mips.h b/src/disassembler_mips.h
new file mode 100644
index 0000000..8c3d0dc
--- /dev/null
+++ b/src/disassembler_mips.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2012 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_SRC_DISASSEMBLER_MIPS_H_
+#define ART_SRC_DISASSEMBLER_MIPS_H_
+
+#include <vector>
+
+#include "disassembler.h"
+
+namespace art {
+namespace mips {
+
+class DisassemblerMips : public Disassembler {
+ public:
+ DisassemblerMips();
+ virtual void Dump(std::ostream& os, const uint8_t* begin, const uint8_t* end);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DisassemblerMips);
+};
+
+} // namespace mips
+} // namespace art
+
+#endif // ART_SRC_DISASSEMBLER_MIPS_H_
diff --git a/src/globals.h b/src/globals.h
index 35a2113..5f0987a 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -46,6 +46,9 @@
// ARM instruction alignment. ARM processors require code to be 4-byte aligned.
const int kArmAlignment = 4;
+// MIPS instruction alignment. MIPS processors require code to be 4-byte aligned.
+const int kMipsAlignment = 4;
+
// X86 instruction alignment. This is the recommended alignment for maximum performance.
const int kX86Alignment = 16;
diff --git a/src/jdwp/jdwp_handler.cc b/src/jdwp/jdwp_handler.cc
index 355fc5e..cf1e188 100644
--- a/src/jdwp/jdwp_handler.cc
+++ b/src/jdwp/jdwp_handler.cc
@@ -1016,9 +1016,7 @@
* Get the monitor that the thread is waiting on.
*/
static JdwpError handleTR_CurrentContendedMonitor(JdwpState*, const uint8_t* buf, int, ExpandBuf*) {
- ObjectId threadId;
-
- threadId = ReadObjectId(&buf);
+ ReadObjectId(&buf); // threadId
// TODO: create an Object to represent the monitor (we're currently
// just using a raw Monitor struct in the VM)
@@ -1143,8 +1141,7 @@
}
static JdwpError handleCLR_VisibleClasses(JdwpState*, const uint8_t* buf, int, ExpandBuf* pReply) {
- ObjectId classLoaderObject;
- classLoaderObject = ReadObjectId(&buf);
+ ReadObjectId(&buf); // classLoaderObject
// TODO: we should only return classes which have the given class loader as a defining or
// initiating loader. The former would be easy; the latter is hard, because we don't have
// any such notion.
@@ -1629,7 +1626,7 @@
* so waitForDebugger() doesn't return if we stall for a bit here.
*/
Dbg::GoActive();
- QuasiAtomicSwap64(0, &lastActivityWhen);
+ QuasiAtomic::Swap64(0, &lastActivityWhen);
}
/*
@@ -1698,7 +1695,7 @@
* the initial setup. Only update if this is a non-DDMS packet.
*/
if (pHeader->cmdSet != kJDWPDdmCmdSet) {
- QuasiAtomicSwap64(MilliTime(), &lastActivityWhen);
+ QuasiAtomic::Swap64(MilliTime(), &lastActivityWhen);
}
/* tell the VM that GC is okay again */
diff --git a/src/jdwp/jdwp_main.cc b/src/jdwp/jdwp_main.cc
index a820cc1..df24b8c 100644
--- a/src/jdwp/jdwp_main.cc
+++ b/src/jdwp/jdwp_main.cc
@@ -416,7 +416,7 @@
return -1;
}
- int64_t last = QuasiAtomicRead64(&lastActivityWhen);
+ int64_t last = QuasiAtomic::Read64(&lastActivityWhen);
/* initializing or in the middle of something? */
if (last == 0) {
diff --git a/src/jdwp/jdwp_socket.cc b/src/jdwp/jdwp_socket.cc
index 9ff50f5..01eba12 100644
--- a/src/jdwp/jdwp_socket.cc
+++ b/src/jdwp/jdwp_socket.cc
@@ -558,7 +558,6 @@
JdwpReqHeader hdr;
uint32_t length, id;
uint8_t flags, cmdSet, cmd;
- uint16_t error;
bool reply;
int dataLen;
@@ -571,7 +570,7 @@
flags = Read1(&buf);
if ((flags & kJDWPFlagReply) != 0) {
reply = true;
- error = Read2BE(&buf);
+ Read2BE(&buf); // error
} else {
reply = false;
cmdSet = Read1(&buf);
diff --git a/src/native/sun_misc_Unsafe.cc b/src/native/sun_misc_Unsafe.cc
index 214771b..8cc549a 100644
--- a/src/native/sun_misc_Unsafe.cc
+++ b/src/native/sun_misc_Unsafe.cc
@@ -54,7 +54,7 @@
byte* raw_addr = reinterpret_cast<byte*>(obj) + offset;
volatile int64_t* address = reinterpret_cast<volatile int64_t*>(raw_addr);
// Note: android_atomic_cmpxchg() returns 0 on success, not failure.
- int result = QuasiAtomicCas64(expectedValue, newValue, address);
+ int result = QuasiAtomic::Cas64(expectedValue, newValue, address);
return (result == 0);
}
diff --git a/src/oat/jni/arm/jni_internal_arm.cc b/src/oat/jni/arm/jni_internal_arm.cc
index 2227742..78c3903 100644
--- a/src/oat/jni/arm/jni_internal_arm.cc
+++ b/src/oat/jni/arm/jni_internal_arm.cc
@@ -71,12 +71,7 @@
// Can either get 3 or 2 arguments into registers
size_t reg_bytes = (is_static ? 3 : 2) * kPointerSize;
- // Bytes passed by stack
- size_t stack_bytes;
- if (num_arg_array_bytes > reg_bytes) {
- stack_bytes = num_arg_array_bytes - reg_bytes;
- } else {
- stack_bytes = 0;
+ if (num_arg_array_bytes <= reg_bytes) {
reg_bytes = num_arg_array_bytes;
}
diff --git a/src/oat/runtime/arm/runtime_support_arm.S b/src/oat/runtime/arm/runtime_support_arm.S
index 2ef162e..638a7c3 100644
--- a/src/oat/runtime/arm/runtime_support_arm.S
+++ b/src/oat/runtime/arm/runtime_support_arm.S
@@ -254,7 +254,7 @@
SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case exception allocation triggers GC
mov r2, r9 @ pass Thread::Current
mov r3, sp @ pass SP
- bl artHandleFillArrayDataFromCode @ (Array* array, const uint16_t* table, Thread*, SP)
+ bl artHandleFillArrayDataFromCode @ (Array*, const DexFile::Payload*, Thread*, SP)
RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
cmp r0, #0 @ success?
bxeq lr @ return on success
diff --git a/src/oat/runtime/mips/runtime_support_mips.S b/src/oat/runtime/mips/runtime_support_mips.S
index 9b082bf..d4e87c0 100644
--- a/src/oat/runtime/mips/runtime_support_mips.S
+++ b/src/oat/runtime/mips/runtime_support_mips.S
@@ -416,7 +416,7 @@
art_handle_fill_data_from_code:
SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case exception allocation triggers GC
move a2, rSELF @ pass Thread::Current
- jal artHandleFillArrayDataFromCode @ (Array* array, const uint16_t* table, Thread*, SP)
+ jal artHandleFillArrayDataFromCode @ (Array*, const DexFile::Payload*, Thread*, SP)
move a3, sp @ pass SP
RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
bnez v0, 1f @ success?
diff --git a/src/oat/runtime/support_fillarray.cc b/src/oat/runtime/support_fillarray.cc
index eb1c46c..6f40177 100644
--- a/src/oat/runtime/support_fillarray.cc
+++ b/src/oat/runtime/support_fillarray.cc
@@ -15,6 +15,7 @@
*/
#include "callee_save_frame.h"
+#include "dex_instruction.h"
#include "object.h"
namespace art {
@@ -34,25 +35,24 @@
* ubyte data[size*width] table of data values (may contain a single-byte
* padding at the end)
*/
-extern "C" int artHandleFillArrayDataFromCode(Array* array, const uint16_t* table,
+extern "C" int artHandleFillArrayDataFromCode(Array* array, const DexFile::Payload* payload,
Thread* self, Method** sp) {
FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- DCHECK_EQ(table[0], 0x0300);
+ DCHECK_EQ(payload->ident, static_cast<uint16_t>(Instruction::kArrayDataSignature));
if (UNLIKELY(array == NULL)) {
Thread::Current()->ThrowNewExceptionF("Ljava/lang/NullPointerException;",
- "null array in fill array");
+ "null array in FILL_ARRAY_DATA");
return -1; // Error
}
DCHECK(array->IsArrayInstance() && !array->IsObjectArray());
- uint32_t size = (uint32_t)table[2] | (((uint32_t)table[3]) << 16);
- if (UNLIKELY(static_cast<int32_t>(size) > array->GetLength())) {
+ if (UNLIKELY(static_cast<int32_t>(payload->element_count) > array->GetLength())) {
Thread::Current()->ThrowNewExceptionF("Ljava/lang/ArrayIndexOutOfBoundsException;",
- "failed array fill. length=%d; index=%d", array->GetLength(), size);
+ "failed FILL_ARRAY_DATA; length=%d, index=%d",
+ array->GetLength(), payload->element_count);
return -1; // Error
}
- uint16_t width = table[1];
- uint32_t size_in_bytes = size * width;
- memcpy((char*)array + Array::DataOffset(width).Int32Value(), (char*)&table[4], size_in_bytes);
+ uint32_t size_in_bytes = payload->element_count * payload->element_width;
+ memcpy(array->GetRawData(payload->element_width), payload->data, size_in_bytes);
return 0; // Success
}
diff --git a/src/oat/runtime/support_stubs.cc b/src/oat/runtime/support_stubs.cc
index ac5d6f9..2a46c8b 100644
--- a/src/oat/runtime/support_stubs.cc
+++ b/src/oat/runtime/support_stubs.cc
@@ -89,8 +89,10 @@
bool is_static;
bool is_virtual;
uint32_t dex_method_idx;
+#if !defined(__i386__)
const char* shorty;
uint32_t shorty_len;
+#endif
if (type == Runtime::kUnknownMethod) {
DCHECK(called->IsRuntimeMethod());
// less two as return address may span into next dex instruction
@@ -109,15 +111,19 @@
(instr_code == Instruction::INVOKE_DIRECT_RANGE));
DecodedInstruction dec_insn(instr);
dex_method_idx = dec_insn.vB;
+#if !defined(__i386__)
shorty = linker->MethodShorty(dex_method_idx, caller, &shorty_len);
+#endif
} else {
DCHECK(!called->IsRuntimeMethod());
is_static = type == Runtime::kStaticMethod;
is_virtual = false;
dex_method_idx = called->GetDexMethodIndex();
+#if !defined(__i386__)
MethodHelper mh(called);
shorty = mh.GetShorty();
shorty_len = mh.GetShortyLength();
+#endif
}
#if !defined(__i386__)
// Discover shorty (avoid GCs)
diff --git a/src/oat_writer.cc b/src/oat_writer.cc
index 4d11237..ffdb0c8 100644
--- a/src/oat_writer.cc
+++ b/src/oat_writer.cc
@@ -258,8 +258,10 @@
uint32_t method_idx, const DexFile* dex_file) {
// derived from CompiledMethod if available
uint32_t code_offset = 0;
+#if defined(ART_USE_LLVM_COMPILER)
uint16_t code_elf_idx = static_cast<uint16_t>(-1u);
uint16_t code_elf_func_idx = static_cast<uint16_t>(-1u);
+#endif
uint32_t frame_size_in_bytes = kStackAlignment;
uint32_t core_spill_mask = 0;
uint32_t fp_spill_mask = 0;
@@ -268,15 +270,19 @@
uint32_t gc_map_offset = 0;
// derived from CompiledInvokeStub if available
uint32_t invoke_stub_offset = 0;
+#if defined(ART_USE_LLVM_COMPILER)
uint16_t invoke_stub_elf_idx = static_cast<uint16_t>(-1u);
uint16_t invoke_stub_elf_func_idx = static_cast<uint16_t>(-1u);
+#endif
CompiledMethod* compiled_method =
compiler_->GetCompiledMethod(Compiler::MethodReference(dex_file, method_idx));
if (compiled_method != NULL) {
if (compiled_method->IsExecutableInElf()) {
+#if defined(ART_USE_LLVM_COMPILER)
code_elf_idx = compiled_method->GetElfIndex();
code_elf_func_idx = compiled_method->GetElfFuncIndex();
+#endif
frame_size_in_bytes = compiled_method->GetFrameSizeInBytes();
} else {
offset = compiled_method->AlignCode(offset);
@@ -359,8 +365,10 @@
const CompiledInvokeStub* compiled_invoke_stub = compiler_->FindInvokeStub(is_static, shorty);
if (compiled_invoke_stub != NULL) {
if (compiled_invoke_stub->IsExecutableInElf()) {
+#if defined(ART_USE_LLVM_COMPILER)
invoke_stub_elf_idx = compiled_invoke_stub->GetElfIndex();
invoke_stub_elf_func_idx = compiled_invoke_stub->GetElfFuncIndex();
+#endif
} else {
offset = CompiledMethod::AlignCode(offset, compiler_->GetInstructionSet());
DCHECK_ALIGNED(offset, kArmAlignment);
@@ -600,10 +608,6 @@
const CompiledMethod* compiled_method =
compiler_->GetCompiledMethod(Compiler::MethodReference(&dex_file, method_idx));
- uint32_t frame_size_in_bytes = 0;
- uint32_t core_spill_mask = 0;
- uint32_t fp_spill_mask = 0;
-
OatMethodOffsets method_offsets =
oat_classes_[oat_class_index]->method_offsets_[class_def_method_index];
@@ -647,9 +651,6 @@
code_offset += code_size;
}
DCHECK_CODE_OFFSET();
- frame_size_in_bytes = compiled_method->GetFrameSizeInBytes();
- core_spill_mask = compiled_method->GetCoreSpillMask();
- fp_spill_mask = compiled_method->GetFpSpillMask();
const std::vector<uint32_t>& mapping_table = compiled_method->GetMappingTable();
size_t mapping_table_size = mapping_table.size() * sizeof(mapping_table[0]);
diff --git a/src/object.h b/src/object.h
index 5e67f62..f5970f6 100644
--- a/src/object.h
+++ b/src/object.h
@@ -361,7 +361,7 @@
const byte* raw_addr = reinterpret_cast<const byte*>(this) + field_offset.Int32Value();
const int64_t* addr = reinterpret_cast<const int64_t*>(raw_addr);
if (UNLIKELY(is_volatile)) {
- uint64_t result = QuasiAtomicRead64(addr);
+ uint64_t result = QuasiAtomic::Read64(addr);
ANDROID_MEMBAR_FULL();
return result;
} else {
@@ -375,7 +375,7 @@
int64_t* addr = reinterpret_cast<int64_t*>(raw_addr);
if (UNLIKELY(is_volatile)) {
ANDROID_MEMBAR_STORE();
- QuasiAtomicSwap64(new_value, addr);
+ QuasiAtomic::Swap64(new_value, addr);
// Post-store barrier not required due to use of atomic op or mutex.
} else {
*addr = new_value;
diff --git a/src/runtime.cc b/src/runtime.cc
index a94a93a..aabd86f 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -108,6 +108,8 @@
delete intern_table_;
delete java_vm_;
Thread::Shutdown();
+ QuasiAtomic::Shutdown();
+
// TODO: acquire a static mutex on Runtime to avoid racing.
CHECK(instance_ == NULL || instance_ == this);
instance_ = NULL;
@@ -615,6 +617,8 @@
}
VLOG(startup) << "Runtime::Init -verbose:startup enabled";
+ QuasiAtomic::Startup();
+
SetJniGlobalsMax(options->jni_globals_max_);
Monitor::Init(options->lock_profiling_threshold_, options->hook_is_sensitive_thread_);
diff --git a/src/runtime_linux.cc b/src/runtime_linux.cc
index 75540b8..e2c806d 100644
--- a/src/runtime_linux.cc
+++ b/src/runtime_linux.cc
@@ -118,7 +118,7 @@
case SIGILL: return "SIGILL";
case SIGPIPE: return "SIGPIPE";
case SIGSEGV: return "SIGSEGV";
-#if defined(STIGSTLFKT)
+#if defined(SIGSTKFLT)
case SIGSTKFLT: return "SIGSTKFLT";
#endif
case SIGTRAP: return "SIGTRAP";
diff --git a/src/thread.cc b/src/thread.cc
index 7f971c4..4554cee 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -412,9 +412,9 @@
size_t old_stack_size = stack_size_;
stack_size_ = default_stack_size;
stack_begin_ += (old_stack_size - stack_size_);
- LOG(WARNING) << "Limiting unlimited stack (reported as " << PrettySize(old_stack_size) << ")"
- << " to " << PrettySize(stack_size_)
- << " with base " << reinterpret_cast<void*>(stack_begin_);
+ VLOG(threads) << "Limiting unlimited stack (reported as " << PrettySize(old_stack_size) << ")"
+ << " to " << PrettySize(stack_size_)
+ << " with base " << reinterpret_cast<void*>(stack_begin_);
}
}
#endif
@@ -502,7 +502,7 @@
// Grab the scheduler stats for this thread.
std::string scheduler_stats;
- if (ReadFileToString(StringPrintf("/proc/self/task/%d/schedstat", GetTid()).c_str(), &scheduler_stats)) {
+ if (ReadFileToString(StringPrintf("/proc/self/task/%d/schedstat", GetTid()), &scheduler_stats)) {
scheduler_stats.resize(scheduler_stats.size() - 1); // Lose the trailing '\n'.
} else {
scheduler_stats = "0 0 0";
@@ -564,6 +564,9 @@
}
virtual ~StackDumpVisitor() {
+ if (frame_count == 0) {
+ os << " (no managed stack frames)\n";
+ }
}
bool VisitFrame(const Frame& frame, uintptr_t pc) {
@@ -620,12 +623,35 @@
void Thread::DumpStack(std::ostream& os) const {
// If we're currently in native code, dump that stack before dumping the managed stack.
if (GetState() == kNative || GetState() == kVmWait) {
+ DumpKernelStack(os);
DumpNativeStack(os);
}
StackDumpVisitor dumper(os, this);
WalkStack(&dumper);
}
+#if !defined(__APPLE__)
+void Thread::DumpKernelStack(std::ostream& os) const {
+ std::string kernel_stack_filename(StringPrintf("/proc/self/task/%d/stack", GetTid()));
+ std::string kernel_stack;
+ if (!ReadFileToString(kernel_stack_filename, &kernel_stack)) {
+ os << " (couldn't read " << kernel_stack_filename << ")";
+ }
+
+ std::vector<std::string> kernel_stack_frames;
+ Split(kernel_stack, '\n', kernel_stack_frames);
+ // We skip the last stack frame because it's always equivalent to "[<ffffffff>] 0xffffffff",
+ // which looking at the source appears to be the kernel's way of saying "that's all, folks!".
+ kernel_stack_frames.pop_back();
+ for (size_t i = 0; i < kernel_stack_frames.size(); ++i) {
+ os << " kernel: " << kernel_stack_frames[i] << "\n";
+ }
+}
+#else
+// TODO: can we get the kernel stack on Mac OS?
+void Thread::DumpKernelStack(std::ostream&) const {}
+#endif
+
void Thread::SetStateWithoutSuspendCheck(ThreadState new_state) {
volatile void* raw = reinterpret_cast<volatile void*>(&state_);
volatile int32_t* addr = reinterpret_cast<volatile int32_t*>(raw);
diff --git a/src/thread.h b/src/thread.h
index c5695cf..8ff9dfb 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -484,6 +484,7 @@
void DumpState(std::ostream& os) const;
void DumpStack(std::ostream& os) const;
+ void DumpKernelStack(std::ostream& os) const;
void DumpNativeStack(std::ostream& os) const;
// Out-of-line conveniences for debugging in gdb.
diff --git a/src/thread_android.cc b/src/thread_android.cc
index d26f446..4d982b1 100644
--- a/src/thread_android.cc
+++ b/src/thread_android.cc
@@ -97,6 +97,7 @@
os << " (unwind_backtrace_thread failed for thread " << GetTid() << ".)";
return;
} else if (frame_count == 0) {
+ os << " (no native stack frames)";
return;
}
diff --git a/src/utils.cc b/src/utils.cc
index bfa0c4f..629d513 100644
--- a/src/utils.cc
+++ b/src/utils.cc
@@ -855,7 +855,7 @@
void GetTaskStats(pid_t tid, int& utime, int& stime, int& task_cpu) {
utime = stime = task_cpu = 0;
std::string stats;
- if (!ReadFileToString(StringPrintf("/proc/self/task/%d/stat", tid).c_str(), &stats)) {
+ if (!ReadFileToString(StringPrintf("/proc/self/task/%d/stat", tid), &stats)) {
return;
}
// Skip the command, which may contain spaces.
diff --git a/src/verifier/method_verifier.cc b/src/verifier/method_verifier.cc
index 60b17d6..7d56fa7 100644
--- a/src/verifier/method_verifier.cc
+++ b/src/verifier/method_verifier.cc
@@ -1848,7 +1848,7 @@
case Instruction::INVOKE_DIRECT_RANGE: {
bool is_range = (dec_insn.opcode == Instruction::INVOKE_DIRECT_RANGE);
Method* called_method = VerifyInvocationArgs(dec_insn, METHOD_DIRECT, is_range, false);
- if (called_method != NULL) {
+ if (called_method != NULL && called_method->IsConstructor()) {
/*
* Some additional checks when calling a constructor. We know from the invocation arg check
* that the "this" argument is an instance of called_method->klass. Now we further restrict
@@ -1856,56 +1856,36 @@
* allowing the latter only if the "this" argument is the same as the "this" argument to
* this method (which implies that we're in a constructor ourselves).
*/
- if (called_method->IsConstructor()) {
- const RegType& this_type = work_line_->GetInvocationThis(dec_insn);
- if (this_type.IsConflict()) // failure.
- break;
+ const RegType& this_type = work_line_->GetInvocationThis(dec_insn);
+ if (this_type.IsConflict()) // failure.
+ break;
- /* no null refs allowed (?) */
- if (this_type.IsZero()) {
- Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "unable to initialize null ref";
- break;
- }
- if (called_method != NULL) {
- /* must be in same class or in superclass */
- const RegType& this_super_klass = this_type.GetSuperClass(®_types_);
- if (this_super_klass.IsConflict()) {
- // Unknown super class, fail so we re-check at runtime.
- Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "super class unknown for '" << this_type << "'";
- break;
- } else {
- if (!this_super_klass.IsZero() &&
- called_method->GetDeclaringClass() == this_super_klass.GetClass()) {
- if (this_type.GetClass() != GetDeclaringClass().GetClass()) {
- Fail(VERIFY_ERROR_BAD_CLASS_HARD)
- << "invoke-direct <init> on super only allowed for 'this' in <init>"
- << " (this class '" << this_type << "', called class '"
- << PrettyDescriptor(called_method->GetDeclaringClass()) << "')";
- break;
- }
- } else if (this_type.GetClass() != called_method->GetDeclaringClass()) {
- Fail(VERIFY_ERROR_BAD_CLASS_HARD)
- << "invoke-direct <init> must be on current class or super"
- << " (current class '" << this_type << "', called class '"
- << PrettyDescriptor(called_method->GetDeclaringClass()) << "')";
- break;
- }
- }
- }
-
- /* arg must be an uninitialized reference */
- if (!this_type.IsUninitializedTypes()) {
- Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Expected initialization on uninitialized reference "
- << this_type;
- break;
- }
-
- /*
- * Replace the uninitialized reference with an initialized one. We need to do this for all
- * registers that have the same object instance in them, not just the "this" register.
- */
- work_line_->MarkRefsAsInitialized(this_type);
+ /* no null refs allowed (?) */
+ if (this_type.IsZero()) {
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "unable to initialize null ref";
+ break;
}
+
+ /* must be in same class or in superclass */
+ const RegType& this_super_klass = this_type.GetSuperClass(®_types_);
+ if (this_super_klass.IsConflict()) {
+ // Unknown super class, fail so we re-check at runtime.
+ Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "super class unknown for '" << this_type << "'";
+ break;
+ }
+
+ /* arg must be an uninitialized reference */
+ if (!this_type.IsUninitializedTypes()) {
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Expected initialization on uninitialized reference "
+ << this_type;
+ break;
+ }
+
+ /*
+ * Replace the uninitialized reference with an initialized one. We need to do this for all
+ * registers that have the same object instance in them, not just the "this" register.
+ */
+ work_line_->MarkRefsAsInitialized(this_type);
}
const char* descriptor;
if (called_method == NULL) {
@@ -2226,7 +2206,7 @@
if (have_pending_hard_failure_) {
if (!Runtime::Current()->IsStarted()) {
- /* When compiling, check that the first failure is a hard failure */
+ /* When compiling, check that the last failure is a hard failure */
CHECK_EQ(failures_[failures_.size() - 1], VERIFY_ERROR_BAD_CLASS_HARD);
}
/* immediate failure, reject class */
@@ -2540,7 +2520,7 @@
if (!referrer.CanAccessMember(res_method->GetDeclaringClass(), res_method->GetAccessFlags())) {
Fail(VERIFY_ERROR_ACCESS_METHOD) << "illegal method access (call " << PrettyMethod(res_method)
<< " from " << referrer << ")";
- return NULL;
+ return res_method;
}
// Check that invoke-virtual and invoke-super are not used on private methods of the same class.
if (res_method->IsPrivate() && method_type == METHOD_VIRTUAL) {
@@ -2585,20 +2565,20 @@
if (is_super) {
DCHECK(method_type == METHOD_VIRTUAL);
const RegType& super = GetDeclaringClass().GetSuperClass(®_types_);
+ if (super.IsConflict()) { // unknown super class
+ Fail(VERIFY_ERROR_NO_METHOD) << "unknown super class in invoke-super from "
+ << PrettyMethod(method_idx_, *dex_file_)
+ << " to super " << PrettyMethod(res_method);
+ return NULL;
+ }
Class* super_klass = super.GetClass();
if (res_method->GetMethodIndex() >= super_klass->GetVTable()->GetLength()) {
- if (super.IsConflict()) { // Only Object has no super class
- Fail(VERIFY_ERROR_NO_METHOD) << "invalid invoke-super from "
- << PrettyMethod(method_idx_, *dex_file_)
- << " to super " << PrettyMethod(res_method);
- } else {
- MethodHelper mh(res_method);
- Fail(VERIFY_ERROR_NO_METHOD) << "invalid invoke-super from "
- << PrettyMethod(method_idx_, *dex_file_)
- << " to super " << super
- << "." << mh.GetName()
- << mh.GetSignature();
- }
+ MethodHelper mh(res_method);
+ Fail(VERIFY_ERROR_NO_METHOD) << "invalid invoke-super from "
+ << PrettyMethod(method_idx_, *dex_file_)
+ << " to super " << super
+ << "." << mh.GetName()
+ << mh.GetSignature();
return NULL;
}
}
@@ -2663,7 +2643,7 @@
const RegType& reg_type = reg_types_.FromDescriptor(class_loader_, descriptor);
uint32_t get_reg = is_range ? dec_insn.vC + actual_args : dec_insn.arg[actual_args];
if (!work_line_->VerifyRegisterType(get_reg, reg_type)) {
- return NULL;
+ return res_method;
}
actual_args = reg_type.IsLongOrDoubleTypes() ? actual_args + 2 : actual_args + 1;
}
@@ -2914,7 +2894,6 @@
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "expected field " << PrettyField(field)
<< " to be of type '" << insn_type
<< "' but found type '" << field_type << "' in get";
- work_line_->SetRegisterType(dec_insn.vA, reg_types_.Conflict());
return;
}
} else {
@@ -3021,10 +3000,10 @@
size_t failure_number = failures_.size();
CHECK_NE(failure_number, 0U);
DCHECK_EQ(failure_messages_.size(), failure_number);
- std::ostringstream* failure_message = failure_messages_[failure_number - 1];
- VerifyError failure = failures_[failure_number - 1];
- failures_.pop_back();
- failure_messages_.pop_back();
+ std::ostringstream* failure_message = failure_messages_[0];
+ VerifyError failure = failures_[0];
+ failures_.clear();
+ failure_messages_.clear();
have_pending_rewrite_failure_ = false;
if (Runtime::Current()->IsStarted()) {
diff --git a/src/verifier/reg_type.h b/src/verifier/reg_type.h
index 9f89d07..6f0193f 100644
--- a/src/verifier/reg_type.h
+++ b/src/verifier/reg_type.h
@@ -144,13 +144,11 @@
}
bool IsReferenceTypes() const {
- return IsReference() || IsUnresolvedReference() || IsZero() ||
- IsUninitializedReference() || IsUninitializedThisReference() ||
- IsUnresolvedAndUninitializedReference() || IsUnresolvedAndUninitializedThisReference();
+ return IsNonZeroReferenceTypes() || IsZero();
}
bool IsNonZeroReferenceTypes() const {
- return IsReference() || IsUnresolvedReference() || IsZero() ||
- IsUninitializedReference() || IsUninitializedThisReference() ||
+ return IsReference() || IsUnresolvedReference() ||
+ IsUninitializedReference() || IsUninitializedThisReference() ||
IsUnresolvedAndUninitializedReference() || IsUnresolvedAndUninitializedThisReference();
}
bool IsCategory1Types() const {