summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorBrian Carlstrom <bdc@google.com>2013-07-10 08:46:00 -0700
committerBrian Carlstrom <bdc@google.com>2013-07-10 08:46:28 -0700
commit2c3caadb48b066a0355cd3d2dcd5d5e9b48fc19c (patch)
treefc53640b73fb2f648e018a15bed8585818f3784f /src
parent75fe90cdb6e358a09047468b750648c8a3bfac9f (diff)
parent0b4e3ef67508a0b8c121b6b26ab5ea0a1d8e7141 (diff)
downloadandroid_art-2c3caadb48b066a0355cd3d2dcd5d5e9b48fc19c.tar.gz
android_art-2c3caadb48b066a0355cd3d2dcd5d5e9b48fc19c.tar.bz2
android_art-2c3caadb48b066a0355cd3d2dcd5d5e9b48fc19c.zip
Merge remote-tracking branch 'goog/dalvik-dev' into merge-art-to-master
Change-Id: Id6bec909d7137192be0acc7bd8f736d1d8027745
Diffstat (limited to 'src')
-rw-r--r--src/atomic.cc17
-rw-r--r--src/atomic_integer.h2
-rw-r--r--src/barrier_test.cc2
-rw-r--r--src/base/macros.h6
-rw-r--r--src/base/mutex.cc6
-rw-r--r--src/base/mutex.h20
-rw-r--r--src/base/stringpiece.cc6
-rw-r--r--src/base/stringpiece.h6
-rw-r--r--src/base/timing_logger.cc116
-rw-r--r--src/base/timing_logger.h58
-rw-r--r--src/check_jni.cc9
-rw-r--r--src/class_linker.cc182
-rw-r--r--src/class_linker.h40
-rw-r--r--src/class_linker_test.cc6
-rw-r--r--src/common_test.h61
-rw-r--r--src/common_throws.cc82
-rw-r--r--src/common_throws.h7
-rw-r--r--src/compiler/dex/arena_bit_vector.cc49
-rw-r--r--src/compiler/dex/arena_bit_vector.h36
-rw-r--r--src/compiler/dex/dataflow_iterator-inl.h68
-rw-r--r--src/compiler/dex/dataflow_iterator.cc63
-rw-r--r--src/compiler/dex/dataflow_iterator.h11
-rw-r--r--src/compiler/dex/dex_to_dex_compiler.cc258
-rw-r--r--src/compiler/dex/frontend.cc7
-rw-r--r--src/compiler/dex/frontend.h7
-rw-r--r--src/compiler/dex/mir_dataflow.cc34
-rw-r--r--src/compiler/dex/mir_graph.cc4
-rw-r--r--src/compiler/dex/mir_graph.h5
-rw-r--r--src/compiler/dex/mir_optimization.cc32
-rw-r--r--src/compiler/dex/portable/mir_to_gbc.cc4
-rw-r--r--src/compiler/dex/quick/arm/assemble_arm.cc1
-rw-r--r--src/compiler/dex/quick/arm/call_arm.cc3
-rw-r--r--src/compiler/dex/quick/arm/codegen_arm.h245
-rw-r--r--src/compiler/dex/quick/arm/fp_arm.cc1
-rw-r--r--src/compiler/dex/quick/arm/int_arm.cc1
-rw-r--r--src/compiler/dex/quick/arm/target_arm.cc1
-rw-r--r--src/compiler/dex/quick/arm/utility_arm.cc2
-rw-r--r--src/compiler/dex/quick/codegen_util.cc169
-rw-r--r--src/compiler/dex/quick/gen_common.cc202
-rw-r--r--src/compiler/dex/quick/gen_invoke.cc197
-rw-r--r--src/compiler/dex/quick/gen_loadstore.cc1
-rw-r--r--src/compiler/dex/quick/mips/assemble_mips.cc1
-rw-r--r--src/compiler/dex/quick/mips/call_mips.cc3
-rw-r--r--src/compiler/dex/quick/mips/codegen_mips.h222
-rw-r--r--src/compiler/dex/quick/mips/fp_mips.cc1
-rw-r--r--src/compiler/dex/quick/mips/int_mips.cc1
-rw-r--r--src/compiler/dex/quick/mips/target_mips.cc1
-rw-r--r--src/compiler/dex/quick/mips/utility_mips.cc1
-rw-r--r--src/compiler/dex/quick/mir_to_lir-inl.h201
-rw-r--r--src/compiler/dex/quick/mir_to_lir.cc12
-rw-r--r--src/compiler/dex/quick/mir_to_lir.h59
-rw-r--r--src/compiler/dex/quick/ralloc_util.cc29
-rw-r--r--src/compiler/dex/quick/x86/assemble_x86.cc1
-rw-r--r--src/compiler/dex/quick/x86/call_x86.cc3
-rw-r--r--src/compiler/dex/quick/x86/codegen_x86.h222
-rw-r--r--src/compiler/dex/quick/x86/fp_x86.cc1
-rw-r--r--src/compiler/dex/quick/x86/int_x86.cc1
-rw-r--r--src/compiler/dex/quick/x86/target_x86.cc1
-rw-r--r--src/compiler/dex/quick/x86/utility_x86.cc1
-rw-r--r--src/compiler/dex/ssa_transformation.cc2
-rw-r--r--src/compiler/dex/vreg_analysis.cc18
-rw-r--r--src/compiler/driver/compiler_driver.cc766
-rw-r--r--src/compiler/driver/compiler_driver.h90
-rw-r--r--src/compiler/driver/compiler_driver_test.cc4
-rw-r--r--src/compiler/driver/dex_compilation_unit.cc30
-rw-r--r--src/compiler/driver/dex_compilation_unit.h6
-rw-r--r--src/compiler/llvm/gbc_expander.cc22
-rw-r--r--src/compiler/llvm/llvm_compilation_unit.h6
-rw-r--r--src/compiler/llvm/runtime_support_builder.cc8
-rw-r--r--src/compiler/llvm/runtime_support_llvm.cc27
-rw-r--r--src/compiler/sea_ir/frontend.cc81
-rw-r--r--src/compiler/sea_ir/sea.cc172
-rw-r--r--src/compiler/sea_ir/sea.h102
-rw-r--r--src/compiler/stubs/portable/stubs.cc136
-rw-r--r--src/compiler/stubs/quick/stubs.cc262
-rw-r--r--src/compiler/stubs/stubs.h59
-rw-r--r--src/debugger.cc24
-rw-r--r--src/dex2oat.cc175
-rw-r--r--src/dex_file.cc78
-rw-r--r--src/dex_file.h26
-rw-r--r--src/dex_file_verifier.cc36
-rw-r--r--src/dex_instruction-inl.h12
-rw-r--r--src/dex_instruction.cc112
-rw-r--r--src/dex_instruction.h71
-rw-r--r--src/dex_instruction_list.h16
-rw-r--r--src/disassembler_arm.cc4
-rw-r--r--src/gc/accounting/atomic_stack.h (renamed from src/gc/atomic_stack.h)46
-rw-r--r--src/gc/accounting/card_table-inl.h (renamed from src/gc/card_table-inl.h)4
-rw-r--r--src/gc/accounting/card_table.cc (renamed from src/gc/card_table.cc)13
-rw-r--r--src/gc/accounting/card_table.h (renamed from src/gc/card_table.h)19
-rw-r--r--src/gc/accounting/heap_bitmap-inl.h (renamed from src/gc/heap_bitmap-inl.h)24
-rw-r--r--src/gc/accounting/heap_bitmap.cc92
-rw-r--r--src/gc/accounting/heap_bitmap.h129
-rw-r--r--src/gc/accounting/mod_union_table-inl.h75
-rw-r--r--src/gc/accounting/mod_union_table.cc (renamed from src/gc/mod_union_table.cc)278
-rw-r--r--src/gc/accounting/mod_union_table.h (renamed from src/gc/mod_union_table.h)114
-rw-r--r--src/gc/accounting/space_bitmap-inl.h (renamed from src/gc/space_bitmap-inl.h)12
-rw-r--r--src/gc/accounting/space_bitmap.cc (renamed from src/gc/space_bitmap.cc)30
-rw-r--r--src/gc/accounting/space_bitmap.h (renamed from src/gc/space_bitmap.h)23
-rw-r--r--src/gc/accounting/space_bitmap_test.cc (renamed from src/gc/space_bitmap_test.cc)5
-rw-r--r--src/gc/allocator/dlmalloc.cc (renamed from src/dlmalloc.cc)25
-rw-r--r--src/gc/allocator/dlmalloc.h (renamed from src/dlmalloc.h)10
-rw-r--r--src/gc/collector/garbage_collector.cc150
-rw-r--r--src/gc/collector/garbage_collector.h (renamed from src/gc/garbage_collector.h)57
-rw-r--r--src/gc/collector/gc_type.cc0
-rw-r--r--src/gc/collector/gc_type.h (renamed from src/gc/gc_type.h)25
-rw-r--r--src/gc/collector/mark_sweep-inl.h (renamed from src/gc/mark_sweep-inl.h)8
-rw-r--r--src/gc/collector/mark_sweep.cc (renamed from src/gc/mark_sweep.cc)477
-rw-r--r--src/gc/collector/mark_sweep.h (renamed from src/gc/mark_sweep.h)125
-rw-r--r--src/gc/collector/partial_mark_sweep.cc (renamed from src/gc/partial_mark_sweep.cc)28
-rw-r--r--src/gc/collector/partial_mark_sweep.h (renamed from src/gc/partial_mark_sweep.h)19
-rw-r--r--src/gc/collector/sticky_mark_sweep.cc66
-rw-r--r--src/gc/collector/sticky_mark_sweep.h (renamed from src/gc/sticky_mark_sweep.h)21
-rw-r--r--src/gc/garbage_collector.cc87
-rw-r--r--src/gc/heap.cc (renamed from src/heap.cc)832
-rw-r--r--src/gc/heap.h (renamed from src/heap.h)296
-rw-r--r--src/gc/heap_bitmap.cc49
-rw-r--r--src/gc/heap_bitmap.h104
-rw-r--r--src/gc/heap_test.cc (renamed from src/heap_test.cc)17
-rw-r--r--src/gc/mod_union_table-inl.h64
-rw-r--r--src/gc/space.h463
-rw-r--r--src/gc/space/dlmalloc_space.cc (renamed from src/gc/space.cc)315
-rw-r--r--src/gc/space/dlmalloc_space.h185
-rw-r--r--src/gc/space/image_space.cc129
-rw-r--r--src/gc/space/image_space.h81
-rw-r--r--src/gc/space/large_object_space.cc (renamed from src/gc/large_object_space.cc)13
-rw-r--r--src/gc/space/large_object_space.h (renamed from src/gc/large_object_space.h)55
-rw-r--r--src/gc/space/space-inl.h53
-rw-r--r--src/gc/space/space.cc47
-rw-r--r--src/gc/space/space.h295
-rw-r--r--src/gc/space/space_test.cc (renamed from src/gc/space_test.cc)21
-rw-r--r--src/gc/sticky_mark_sweep.cc64
-rw-r--r--src/hprof/hprof.cc7
-rw-r--r--src/image_test.cc62
-rw-r--r--src/image_writer.cc156
-rw-r--r--src/image_writer.h31
-rw-r--r--src/instrumentation.cc4
-rw-r--r--src/instrumentation.h18
-rw-r--r--src/intern_table.cc6
-rw-r--r--src/intern_table.h2
-rw-r--r--src/interpreter/interpreter.cc861
-rw-r--r--src/interpreter/interpreter.h4
-rw-r--r--src/jni_internal.cc2
-rw-r--r--src/jni_internal_test.cc1
-rw-r--r--src/locks.cc5
-rw-r--r--src/locks.h4
-rw-r--r--src/mem_map.cc22
-rw-r--r--src/mem_map.h2
-rw-r--r--src/mirror/abstract_method-inl.h3
-rw-r--r--src/mirror/abstract_method.cc53
-rw-r--r--src/mirror/abstract_method.h13
-rw-r--r--src/mirror/array.cc10
-rw-r--r--src/mirror/array.h7
-rw-r--r--src/mirror/class.cc19
-rw-r--r--src/mirror/class.h20
-rw-r--r--src/mirror/dex_cache-inl.h40
-rw-r--r--src/mirror/dex_cache.cc16
-rw-r--r--src/mirror/dex_cache_test.cc2
-rw-r--r--src/mirror/field-inl.h2
-rw-r--r--src/mirror/field.cc2
-rw-r--r--src/mirror/object.cc6
-rw-r--r--src/mirror/object_array-inl.h4
-rw-r--r--src/mirror/object_test.cc6
-rw-r--r--src/mirror/stack_trace_element.cc2
-rw-r--r--src/mirror/string.cc2
-rw-r--r--src/mirror/throwable.cc2
-rw-r--r--src/modifiers.h4
-rw-r--r--src/native/dalvik_system_DexFile.cc14
-rw-r--r--src/native/dalvik_system_VMRuntime.cc16
-rw-r--r--src/native/java_lang_Runtime.cc2
-rw-r--r--src/native/java_lang_System.cc2
-rw-r--r--src/native/java_lang_Thread.cc1
-rw-r--r--src/native/sun_misc_Unsafe.cc2
-rw-r--r--src/oat.cc102
-rw-r--r--src/oat.h18
-rw-r--r--src/oat/runtime/arm/oat_support_entrypoints_arm.cc20
-rw-r--r--src/oat/runtime/arm/runtime_support_arm.S42
-rw-r--r--src/oat/runtime/mips/oat_support_entrypoints_mips.cc20
-rw-r--r--src/oat/runtime/mips/runtime_support_mips.S65
-rw-r--r--src/oat/runtime/oat_support_entrypoints.h28
-rw-r--r--src/oat/runtime/support_dexcache.cc2
-rw-r--r--src/oat/runtime/support_field.cc24
-rw-r--r--src/oat/runtime/support_interpreter.cc7
-rw-r--r--src/oat/runtime/support_invoke.cc1
-rw-r--r--src/oat/runtime/support_stubs.cc34
-rw-r--r--src/oat/runtime/support_throw.cc2
-rw-r--r--src/oat/runtime/x86/oat_support_entrypoints_x86.cc20
-rw-r--r--src/oat/runtime/x86/runtime_support_x86.S49
-rw-r--r--src/oat_test.cc16
-rw-r--r--src/oat_writer.cc177
-rw-r--r--src/oat_writer.h37
-rw-r--r--src/oatdump.cc34
-rw-r--r--src/object_utils.h4
-rw-r--r--src/output_stream_test.cc20
-rw-r--r--src/runtime.cc87
-rw-r--r--src/runtime.h50
-rw-r--r--src/runtime_support.cc39
-rw-r--r--src/runtime_support.h21
-rw-r--r--src/signal_catcher.cc2
-rw-r--r--src/stack.cc9
-rw-r--r--src/stack.h10
-rw-r--r--src/thread-inl.h2
-rw-r--r--src/thread.cc60
-rw-r--r--src/thread.h5
-rw-r--r--src/thread_list.cc4
-rw-r--r--src/thread_pool.cc19
-rw-r--r--src/thread_pool.h2
-rw-r--r--src/thread_pool_test.cc4
-rw-r--r--src/thread_state.h1
-rw-r--r--src/utf.cc17
-rw-r--r--src/utf.h6
-rw-r--r--src/vector_output_stream.cc16
-rw-r--r--src/vector_output_stream.h23
-rw-r--r--src/verifier/method_verifier.cc1312
-rw-r--r--src/verifier/method_verifier.h111
-rw-r--r--src/verifier/reg_type.cc313
-rw-r--r--src/verifier/reg_type.h618
-rw-r--r--src/verifier/reg_type_cache-inl.h8
-rw-r--r--src/verifier/reg_type_cache.cc185
-rw-r--r--src/verifier/reg_type_cache.h11
-rw-r--r--src/verifier/reg_type_test.cc12
-rw-r--r--src/verifier/register_line-inl.h35
-rw-r--r--src/verifier/register_line.cc128
-rw-r--r--src/verifier/register_line.h29
-rw-r--r--src/well_known_classes.cc4
-rw-r--r--src/well_known_classes.h2
226 files changed, 9968 insertions, 5514 deletions
diff --git a/src/atomic.cc b/src/atomic.cc
index 4efb06187b..f2a998289c 100644
--- a/src/atomic.cc
+++ b/src/atomic.cc
@@ -130,20 +130,9 @@ bool QuasiAtomic::Cas64(int64_t old_value, int64_t new_value, volatile int64_t*
} while (__builtin_expect(status != 0, 0));
return prev == old_value;
#elif defined(__i386__)
- // cmpxchg8b implicitly uses %ebx which is also the PIC register.
- int8_t status;
- __asm__ __volatile__ (
- "pushl %%ebx\n"
- "movl (%3), %%ebx\n"
- "movl 4(%3), %%ecx\n"
- "lock cmpxchg8b %1\n"
- "sete %0\n"
- "popl %%ebx"
- : "=R" (status), "+m" (*addr)
- : "A"(old_value), "D" (&new_value)
- : "%ecx"
- );
- return status != 0;
+ // The compiler does the right job and works better than inline assembly, especially with -O0
+ // compilation.
+ return __sync_bool_compare_and_swap(addr, old_value, new_value);
#else
#error Unexpected architecture
#endif
diff --git a/src/atomic_integer.h b/src/atomic_integer.h
index 188f4c28b0..c4a8de9817 100644
--- a/src/atomic_integer.h
+++ b/src/atomic_integer.h
@@ -71,7 +71,7 @@ class AtomicInteger {
return success;
}
private:
- int32_t value_;
+ volatile int32_t value_;
};
}
diff --git a/src/barrier_test.cc b/src/barrier_test.cc
index 093ba3535a..55d2d3d715 100644
--- a/src/barrier_test.cc
+++ b/src/barrier_test.cc
@@ -88,7 +88,7 @@ TEST_F(BarrierTest, CheckWait) {
// at this point.
EXPECT_EQ(num_threads, count2);
// Wait for all the threads to finish.
- thread_pool.Wait(self);
+ thread_pool.Wait(self, true, false);
// All three counts should be equal to num_threads now.
EXPECT_EQ(count1, count2);
EXPECT_EQ(count2, count3);
diff --git a/src/base/macros.h b/src/base/macros.h
index 8579872d58..847105d20c 100644
--- a/src/base/macros.h
+++ b/src/base/macros.h
@@ -136,6 +136,12 @@ char (&ArraySizeHelper(T (&array)[N]))[N];
#define ALWAYS_INLINE __attribute__ ((always_inline))
#endif
+#if defined (__APPLE__)
+#define HOT_ATTR
+#else
+#define HOT_ATTR __attribute__ ((hot))
+#endif
+
// bionic and glibc both have TEMP_FAILURE_RETRY, but Mac OS' libc doesn't.
#ifndef TEMP_FAILURE_RETRY
#define TEMP_FAILURE_RETRY(exp) ({ \
diff --git a/src/base/mutex.cc b/src/base/mutex.cc
index a2851e5b3c..fbec826af2 100644
--- a/src/base/mutex.cc
+++ b/src/base/mutex.cc
@@ -777,6 +777,11 @@ void ConditionVariable::Signal(Thread* self) {
}
void ConditionVariable::Wait(Thread* self) {
+ guard_.CheckSafeToWait(self);
+ WaitHoldingLocks(self);
+}
+
+void ConditionVariable::WaitHoldingLocks(Thread* self) {
DCHECK(self == NULL || self == Thread::Current());
guard_.AssertExclusiveHeld(self);
unsigned int old_recursion_count = guard_.recursion_count_;
@@ -811,6 +816,7 @@ void ConditionVariable::Wait(Thread* self) {
void ConditionVariable::TimedWait(Thread* self, int64_t ms, int32_t ns) {
DCHECK(self == NULL || self == Thread::Current());
guard_.AssertExclusiveHeld(self);
+ guard_.CheckSafeToWait(self);
unsigned int old_recursion_count = guard_.recursion_count_;
#if ART_USE_FUTEXES
timespec rel_ts;
diff --git a/src/base/mutex.h b/src/base/mutex.h
index a3efd5c6f4..24df572e97 100644
--- a/src/base/mutex.h
+++ b/src/base/mutex.h
@@ -53,7 +53,7 @@ namespace art {
class ScopedContentionRecorder;
class Thread;
-const bool kDebugLocking = kIsDebugBuild;
+const bool kDebugLocking = true || kIsDebugBuild;
// Base class for all Mutex implementations
class BaseMutex {
@@ -141,7 +141,7 @@ class LOCKABLE Mutex : public BaseMutex {
// Assert that the Mutex is exclusively held by the current thread.
void AssertExclusiveHeld(const Thread* self) {
- if (kDebugLocking && !gAborting) {
+ if (kDebugLocking && (gAborting == 0)) {
CHECK(IsExclusiveHeld(self)) << *this;
}
}
@@ -149,7 +149,7 @@ class LOCKABLE Mutex : public BaseMutex {
// Assert that the Mutex is not held by the current thread.
void AssertNotHeldExclusive(const Thread* self) {
- if (kDebugLocking) {
+ if (kDebugLocking && (gAborting == 0)) {
CHECK(!IsExclusiveHeld(self)) << *this;
}
}
@@ -238,7 +238,7 @@ class LOCKABLE ReaderWriterMutex : public BaseMutex {
// Assert the current thread has exclusive access to the ReaderWriterMutex.
void AssertExclusiveHeld(const Thread* self) {
- if (kDebugLocking) {
+ if (kDebugLocking & (gAborting == 0)) {
CHECK(IsExclusiveHeld(self)) << *this;
}
}
@@ -246,8 +246,8 @@ class LOCKABLE ReaderWriterMutex : public BaseMutex {
// Assert the current thread doesn't have exclusive access to the ReaderWriterMutex.
void AssertNotExclusiveHeld(const Thread* self) {
- if (kDebugLocking) {
- CHECK(!IsExclusiveHeld(self));
+ if (kDebugLocking & (gAborting == 0)) {
+ CHECK(!IsExclusiveHeld(self)) << *this;
}
}
void AssertNotWriterHeld(const Thread* self) { AssertNotExclusiveHeld(self); }
@@ -257,7 +257,7 @@ class LOCKABLE ReaderWriterMutex : public BaseMutex {
// Assert the current thread has shared access to the ReaderWriterMutex.
void AssertSharedHeld(const Thread* self) {
- if (kDebugLocking) {
+ if (kDebugLocking & (gAborting == 0)) {
// TODO: we can only assert this well when self != NULL.
CHECK(IsSharedHeld(self) || self == NULL) << *this;
}
@@ -267,7 +267,7 @@ class LOCKABLE ReaderWriterMutex : public BaseMutex {
// Assert the current thread doesn't hold this ReaderWriterMutex either in shared or exclusive
// mode.
void AssertNotHeld(const Thread* self) {
- if (kDebugLocking) {
+ if (kDebugLocking && (gAborting == 0)) {
CHECK(!IsSharedHeld(self)) << *this;
}
}
@@ -307,6 +307,10 @@ class ConditionVariable {
// pointer copy, thereby defeating annotalysis.
void Wait(Thread* self) NO_THREAD_SAFETY_ANALYSIS;
void TimedWait(Thread* self, int64_t ms, int32_t ns) NO_THREAD_SAFETY_ANALYSIS;
+ // Variant of Wait that should be used with caution. Doesn't validate that no mutexes are held
+ // when waiting.
+ // TODO: remove this.
+ void WaitHoldingLocks(Thread* self) NO_THREAD_SAFETY_ANALYSIS;
private:
const char* const name_;
diff --git a/src/base/stringpiece.cc b/src/base/stringpiece.cc
index 715d964a12..47140e3247 100644
--- a/src/base/stringpiece.cc
+++ b/src/base/stringpiece.cc
@@ -21,12 +21,6 @@
namespace art {
-bool operator<(const StringPiece& x, const StringPiece& y) {
- const int r = memcmp(x.data(), y.data(),
- std::min(x.size(), y.size()));
- return ((r < 0) || ((r == 0) && (x.size() < y.size())));
-}
-
void StringPiece::CopyToString(std::string* target) const {
target->assign(ptr_, length_);
}
diff --git a/src/base/stringpiece.h b/src/base/stringpiece.h
index 193f5f7e7b..3664218860 100644
--- a/src/base/stringpiece.h
+++ b/src/base/stringpiece.h
@@ -188,7 +188,11 @@ inline bool operator!=(const StringPiece& x, const StringPiece& y) {
return !(x == y);
}
-bool operator<(const StringPiece& x, const StringPiece& y);
+inline bool operator<(const StringPiece& x, const StringPiece& y) {
+ const int r = memcmp(x.data(), y.data(),
+ std::min(x.size(), y.size()));
+ return ((r < 0) || ((r == 0) && (x.size() < y.size())));
+}
inline bool operator>(const StringPiece& x, const StringPiece& y) {
return y < x;
diff --git a/src/base/timing_logger.cc b/src/base/timing_logger.cc
index 6d5586c08f..c7cbbe504f 100644
--- a/src/base/timing_logger.cc
+++ b/src/base/timing_logger.cc
@@ -82,7 +82,7 @@ CumulativeLogger::~CumulativeLogger() {
}
void CumulativeLogger::SetName(const std::string& name) {
- name_ = name;
+ name_.assign(name);
}
void CumulativeLogger::Start() {
@@ -123,13 +123,40 @@ void CumulativeLogger::AddLogger(const TimingLogger &logger) {
}
}
+void CumulativeLogger::AddNewLogger(const base::NewTimingLogger &logger) {
+ MutexLock mu(Thread::Current(), lock_);
+ const std::vector<std::pair<uint64_t, const char*> >& splits = logger.GetSplits();
+ typedef std::vector<std::pair<uint64_t, const char*> >::const_iterator It;
+ if (kIsDebugBuild && splits.size() != histograms_.size()) {
+ LOG(ERROR) << "Mismatch in splits.";
+ typedef std::vector<Histogram<uint64_t> *>::const_iterator It2;
+ It it = splits.begin();
+ It2 it2 = histograms_.begin();
+ while ((it != splits.end()) && (it2 != histograms_.end())) {
+ if (it != splits.end()) {
+ LOG(ERROR) << "\tsplit: " << it->second;
+ ++it;
+ }
+ if (it2 != histograms_.end()) {
+ LOG(ERROR) << "\tpreviously record: " << (*it2)->Name();
+ ++it2;
+ }
+ }
+ }
+ for (It it = splits.begin(), end = splits.end(); it != end; ++it) {
+ std::pair<uint64_t, const char*> split = *it;
+ uint64_t split_time = split.first;
+ const char* split_name = split.second;
+ AddPair(split_name, split_time);
+ }
+}
+
void CumulativeLogger::Dump(std::ostream &os) {
MutexLock mu(Thread::Current(), lock_);
DumpHistogram(os);
}
void CumulativeLogger::AddPair(const std::string &label, uint64_t delta_time) {
-
// Convert delta time to microseconds so that we don't overflow our counters.
delta_time /= kAdjust;
if (index_ >= histograms_.size()) {
@@ -154,4 +181,89 @@ void CumulativeLogger::DumpHistogram(std::ostream &os) {
os << "Done Dumping histograms \n";
}
+
+namespace base {
+
+NewTimingLogger::NewTimingLogger(const char* name, bool precise, bool verbose)
+ : name_(name), precise_(precise), verbose_(verbose),
+ current_split_(NULL), current_split_start_ns_(0) {
+}
+
+void NewTimingLogger::Reset() {
+ current_split_ = NULL;
+ current_split_start_ns_ = 0;
+ splits_.clear();
+}
+
+void NewTimingLogger::StartSplit(const char* new_split_label) {
+ DCHECK(current_split_ == NULL);
+ if (verbose_) {
+ LOG(INFO) << "Begin: " << new_split_label;
+ }
+ current_split_ = new_split_label;
+ current_split_start_ns_ = NanoTime();
+}
+
+// Ends the current split and starts the one given by the label.
+void NewTimingLogger::NewSplit(const char* new_split_label) {
+ DCHECK(current_split_ != NULL);
+ uint64_t current_time = NanoTime();
+ uint64_t split_time = current_time - current_split_start_ns_;
+ splits_.push_back(std::pair<uint64_t, const char*>(split_time, current_split_));
+ if (verbose_) {
+ LOG(INFO) << "End: " << current_split_ << " " << PrettyDuration(split_time) << "\n"
+ << "Begin: " << new_split_label;
+ }
+ current_split_ = new_split_label;
+ current_split_start_ns_ = current_time;
+}
+
+void NewTimingLogger::EndSplit() {
+ DCHECK(current_split_ != NULL);
+ uint64_t current_time = NanoTime();
+ uint64_t split_time = current_time - current_split_start_ns_;
+ if (verbose_) {
+ LOG(INFO) << "End: " << current_split_ << " " << PrettyDuration(split_time);
+ }
+ splits_.push_back(std::pair<uint64_t, const char*>(split_time, current_split_));
+}
+
+uint64_t NewTimingLogger::GetTotalNs() const {
+ uint64_t total_ns = 0;
+ typedef std::vector<std::pair<uint64_t, const char*> >::const_iterator It;
+ for (It it = splits_.begin(), end = splits_.end(); it != end; ++it) {
+ std::pair<uint64_t, const char*> split = *it;
+ total_ns += split.first;
+ }
+ return total_ns;
+}
+
+void NewTimingLogger::Dump(std::ostream &os) const {
+ uint64_t longest_split = 0;
+ uint64_t total_ns = 0;
+ typedef std::vector<std::pair<uint64_t, const char*> >::const_iterator It;
+ for (It it = splits_.begin(), end = splits_.end(); it != end; ++it) {
+ std::pair<uint64_t, const char*> split = *it;
+ uint64_t split_time = split.first;
+ longest_split = std::max(longest_split, split_time);
+ total_ns += split_time;
+ }
+ // Compute which type of unit we will use for printing the timings.
+ TimeUnit tu = GetAppropriateTimeUnit(longest_split);
+ uint64_t divisor = GetNsToTimeUnitDivisor(tu);
+ // Print formatted splits.
+ for (It it = splits_.begin(), end = splits_.end(); it != end; ++it) {
+ std::pair<uint64_t, const char*> split = *it;
+ uint64_t split_time = split.first;
+ if (!precise_ && divisor >= 1000) {
+ // Make the fractional part 0.
+ split_time -= split_time % (divisor / 1000);
+ }
+ os << name_ << ": " << std::setw(8) << FormatDuration(split_time, tu) << " "
+ << split.second << "\n";
+ }
+ os << name_ << ": end, " << NsToMs(total_ns) << " ms\n";
+}
+
+} // namespace base
} // namespace art
diff --git a/src/base/timing_logger.h b/src/base/timing_logger.h
index bbcc286ba4..65732b170d 100644
--- a/src/base/timing_logger.h
+++ b/src/base/timing_logger.h
@@ -45,6 +45,10 @@ class TimingLogger {
friend class CumulativeLogger;
};
+namespace base {
+ class NewTimingLogger;
+} // namespace base
+
class CumulativeLogger {
public:
@@ -61,6 +65,7 @@ class CumulativeLogger {
// parent class that is unable to determine the "name" of a sub-class.
void SetName(const std::string& name);
void AddLogger(const TimingLogger& logger) LOCKS_EXCLUDED(lock_);
+ void AddNewLogger(const base::NewTimingLogger& logger) LOCKS_EXCLUDED(lock_);
private:
@@ -79,6 +84,59 @@ class CumulativeLogger {
DISALLOW_COPY_AND_ASSIGN(CumulativeLogger);
};
+namespace base {
+
+// A replacement to timing logger that know when a split starts for the purposes of logging.
+// TODO: replace uses of TimingLogger with base::NewTimingLogger.
+class NewTimingLogger {
+ public:
+ explicit NewTimingLogger(const char* name, bool precise, bool verbose);
+
+ // Clears current splits and labels.
+ void Reset();
+
+ // Starts a split, a split shouldn't be in progress.
+ void StartSplit(const char* new_split_label);
+
+ // Ends the current split and starts the one given by the label.
+ void NewSplit(const char* new_split_label);
+
+ // Ends the current split and records the end time.
+ void EndSplit();
+
+ uint64_t GetTotalNs() const;
+
+ void Dump(std::ostream& os) const;
+
+ const std::vector<std::pair<uint64_t, const char*> >& GetSplits() const {
+ return splits_;
+ }
+
+ protected:
+ // The name of the timing logger.
+ const std::string name_;
+
+ // Do we want to print the exactly recorded split (true) or round down to the time unit being
+ // used (false).
+ const bool precise_;
+
+ // Verbose logging.
+ const bool verbose_;
+
+ // The name of the current split.
+ const char* current_split_;
+
+ // The nanosecond time the current split started on.
+ uint64_t current_split_start_ns_;
+
+ // Splits are nanosecond times and split names.
+ std::vector<std::pair<uint64_t, const char*> > splits_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(NewTimingLogger);
+};
+
+} // namespace base
} // namespace art
#endif // ART_SRC_TIMING_LOGGER_H_
diff --git a/src/check_jni.cc b/src/check_jni.cc
index 19f8abfee0..403a2eb348 100644
--- a/src/check_jni.cc
+++ b/src/check_jni.cc
@@ -23,7 +23,7 @@
#include "class_linker.h"
#include "class_linker-inl.h"
#include "dex_file-inl.h"
-#include "gc/space.h"
+#include "gc/space/space.h"
#include "mirror/class-inl.h"
#include "mirror/field-inl.h"
#include "mirror/abstract_method-inl.h"
@@ -36,7 +36,7 @@
#include "thread.h"
#define LIBCORE_CPP_JNI_HELPERS
-#include <JNIHelp.h> // from libcore
+#include <JNIHelp.h> // from libcore
#undef LIBCORE_CPP_JNI_HELPERS
namespace art {
@@ -1215,7 +1215,10 @@ class CheckJNI {
}
static void FatalError(JNIEnv* env, const char* msg) {
- CHECK_JNI_ENTRY(kFlag_NullableUtf, "Eu", env, msg);
+ // The JNI specification doesn't say it's okay to call FatalError with a pending exception,
+ // but you're about to abort anyway, and it's quite likely that you have a pending exception,
+ // and it's not unimaginable that you don't know that you do. So we allow it.
+ CHECK_JNI_ENTRY(kFlag_ExcepOkay | kFlag_NullableUtf, "Eu", env, msg);
baseEnv(env)->FatalError(env, msg);
CHECK_JNI_EXIT_VOID();
}
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 70c7ff30b2..68d0fbbc55 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -34,8 +34,10 @@
#include "class_linker-inl.h"
#include "debugger.h"
#include "dex_file-inl.h"
-#include "gc/card_table-inl.h"
-#include "heap.h"
+#include "gc/accounting/card_table-inl.h"
+#include "gc/accounting/heap_bitmap.h"
+#include "gc/heap.h"
+#include "gc/space/image_space.h"
#include "intern_table.h"
#include "interpreter/interpreter.h"
#include "leb128.h"
@@ -44,7 +46,7 @@
#include "mirror/class.h"
#include "mirror/class-inl.h"
#include "mirror/class_loader.h"
-#include "mirror/dex_cache.h"
+#include "mirror/dex_cache-inl.h"
#include "mirror/field-inl.h"
#include "mirror/iftable-inl.h"
#include "mirror/abstract_method.h"
@@ -63,8 +65,6 @@
#include "ScopedLocalRef.h"
#include "scoped_thread_state_change.h"
#include "sirt_ref.h"
-#include "gc/space.h"
-#include "gc/space_bitmap.h"
#include "stack_indirect_reference_table.h"
#include "thread.h"
#include "UniquePtr.h"
@@ -74,7 +74,9 @@
namespace art {
-void artInterpreterToQuickEntry(Thread* self, ShadowFrame* shadow_frame, JValue* result);
+extern "C" void artInterpreterToQuickEntry(Thread* self, MethodHelper& mh,
+ const DexFile::CodeItem* code_item,
+ ShadowFrame* shadow_frame, JValue* result);
static void ThrowNoClassDefFoundError(const char* fmt, ...)
__attribute__((__format__(__printf__, 1, 2)))
@@ -195,12 +197,14 @@ ClassLinker* ClassLinker::CreateFromImage(InternTable* intern_table) {
ClassLinker::ClassLinker(InternTable* intern_table)
// dex_lock_ is recursive as it may be used in stack dumping.
- : dex_lock_("ClassLinker dex lock", kDefaultMutexLevel, true),
+ : dex_lock_("ClassLinker dex lock", kDefaultMutexLevel),
class_roots_(NULL),
array_iftable_(NULL),
init_done_(false),
is_dirty_(false),
- intern_table_(intern_table) {
+ intern_table_(intern_table),
+ portable_resolution_trampoline_(NULL),
+ quick_resolution_trampoline_(NULL) {
CHECK_EQ(arraysize(class_roots_descriptors_), size_t(kClassRootsMax));
}
@@ -212,7 +216,7 @@ void ClassLinker::InitFromCompiler(const std::vector<const DexFile*>& boot_class
// java_lang_Class comes first, it's needed for AllocClass
Thread* self = Thread::Current();
- Heap* heap = Runtime::Current()->GetHeap();
+ gc::Heap* heap = Runtime::Current()->GetHeap();
SirtRef<mirror::Class>
java_lang_Class(self,
down_cast<mirror::Class*>(heap->AllocObject(self, NULL,
@@ -545,7 +549,7 @@ void ClassLinker::FinishInit() {
CHECK_EQ(java_lang_dex.GetFieldId(zombie->GetDexFieldIndex()).type_idx_,
GetClassRoot(kJavaLangObject)->GetDexTypeIndex());
- Heap* heap = Runtime::Current()->GetHeap();
+ gc::Heap* heap = Runtime::Current()->GetHeap();
heap->SetReferenceOffsets(referent->GetOffset(),
queue->GetOffset(),
queueNext->GetOffset(),
@@ -591,7 +595,7 @@ bool ClassLinker::GenerateOatFile(const std::string& dex_filename,
const char* class_path = Runtime::Current()->GetClassPathString().c_str();
- Heap* heap = Runtime::Current()->GetHeap();
+ gc::Heap* heap = Runtime::Current()->GetHeap();
std::string boot_image_option_string("--boot-image=");
boot_image_option_string += heap->GetImageSpace()->GetImageFilename();
const char* boot_image_option = boot_image_option_string.c_str();
@@ -662,22 +666,22 @@ bool ClassLinker::GenerateOatFile(const std::string& dex_filename,
}
void ClassLinker::RegisterOatFile(const OatFile& oat_file) {
- MutexLock mu(Thread::Current(), dex_lock_);
+ WriterMutexLock mu(Thread::Current(), dex_lock_);
RegisterOatFileLocked(oat_file);
}
void ClassLinker::RegisterOatFileLocked(const OatFile& oat_file) {
- dex_lock_.AssertHeld(Thread::Current());
-#ifndef NDEBUG
- for (size_t i = 0; i < oat_files_.size(); ++i) {
- CHECK_NE(&oat_file, oat_files_[i]) << oat_file.GetLocation();
+ dex_lock_.AssertExclusiveHeld(Thread::Current());
+ if (kIsDebugBuild) {
+ for (size_t i = 0; i < oat_files_.size(); ++i) {
+ CHECK_NE(&oat_file, oat_files_[i]) << oat_file.GetLocation();
+ }
}
-#endif
oat_files_.push_back(&oat_file);
}
-OatFile* ClassLinker::OpenOat(const ImageSpace* space) {
- MutexLock mu(Thread::Current(), dex_lock_);
+OatFile* ClassLinker::OpenOat(const gc::space::ImageSpace* space) {
+ WriterMutexLock mu(Thread::Current(), dex_lock_);
const Runtime* runtime = Runtime::Current();
const ImageHeader& image_header = space->GetImageHeader();
// Grab location but don't use Object::AsString as we haven't yet initialized the roots to
@@ -708,7 +712,7 @@ OatFile* ClassLinker::OpenOat(const ImageSpace* space) {
}
const OatFile* ClassLinker::FindOpenedOatFileForDexFile(const DexFile& dex_file) {
- MutexLock mu(Thread::Current(), dex_lock_);
+ ReaderMutexLock mu(Thread::Current(), dex_lock_);
return FindOpenedOatFileFromDexLocation(dex_file.GetLocation());
}
@@ -724,10 +728,9 @@ const OatFile* ClassLinker::FindOpenedOatFileFromDexLocation(const std::string&
return NULL;
}
-static const DexFile* FindDexFileInOatLocation(const std::string& dex_location,
- uint32_t dex_location_checksum,
- const std::string& oat_location)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+const DexFile* ClassLinker::FindDexFileInOatLocation(const std::string& dex_location,
+ uint32_t dex_location_checksum,
+ const std::string& oat_location) {
UniquePtr<OatFile> oat_file(OatFile::Open(oat_location, oat_location, NULL));
if (oat_file.get() == NULL) {
return NULL;
@@ -748,13 +751,13 @@ static const DexFile* FindDexFileInOatLocation(const std::string& dex_location,
if (oat_dex_file->GetDexFileLocationChecksum() != dex_location_checksum) {
return NULL;
}
- runtime->GetClassLinker()->RegisterOatFile(*oat_file.release());
+ RegisterOatFileLocked(*oat_file.release());
return oat_dex_file->OpenDexFile();
}
const DexFile* ClassLinker::FindOrCreateOatFileForDexLocation(const std::string& dex_location,
const std::string& oat_location) {
- MutexLock mu(Thread::Current(), dex_lock_);
+ WriterMutexLock mu(Thread::Current(), dex_lock_);
return FindOrCreateOatFileForDexLocationLocked(dex_location, oat_location);
}
@@ -856,7 +859,7 @@ const DexFile* ClassLinker::VerifyAndOpenDexFileFromOatFile(const OatFile* oat_f
}
const DexFile* ClassLinker::FindDexFileInOatFileFromDexLocation(const std::string& dex_location) {
- MutexLock mu(Thread::Current(), dex_lock_);
+ WriterMutexLock mu(Thread::Current(), dex_lock_);
const OatFile* open_oat_file = FindOpenedOatFileFromDexLocation(dex_location);
if (open_oat_file != NULL) {
@@ -923,7 +926,7 @@ const OatFile* ClassLinker::FindOpenedOatFileFromOatLocation(const std::string&
}
const OatFile* ClassLinker::FindOatFileFromOatLocation(const std::string& oat_location) {
- MutexLock mu(Thread::Current(), dex_lock_);
+ ReaderMutexLock mu(Thread::Current(), dex_lock_);
return FindOatFileFromOatLocationLocked(oat_location);
}
@@ -944,13 +947,15 @@ void ClassLinker::InitFromImage() {
VLOG(startup) << "ClassLinker::InitFromImage entering";
CHECK(!init_done_);
- Heap* heap = Runtime::Current()->GetHeap();
- ImageSpace* space = heap->GetImageSpace();
+ gc::Heap* heap = Runtime::Current()->GetHeap();
+ gc::space::ImageSpace* space = heap->GetImageSpace();
OatFile* oat_file = OpenOat(space);
CHECK(oat_file != NULL) << "Failed to open oat file for image";
CHECK_EQ(oat_file->GetOatHeader().GetImageFileLocationOatChecksum(), 0U);
CHECK_EQ(oat_file->GetOatHeader().GetImageFileLocationOatDataBegin(), 0U);
CHECK(oat_file->GetOatHeader().GetImageFileLocation().empty());
+ portable_resolution_trampoline_ = oat_file->GetOatHeader().GetPortableResolutionTrampoline();
+ quick_resolution_trampoline_ = oat_file->GetOatHeader().GetQuickResolutionTrampoline();
mirror::Object* dex_caches_object = space->GetImageHeader().GetImageRoot(ImageHeader::kDexCaches);
mirror::ObjectArray<mirror::DexCache>* dex_caches =
dex_caches_object->AsObjectArray<mirror::DexCache>();
@@ -1037,17 +1042,14 @@ void ClassLinker::InitFromImageCallback(mirror::Object* obj, void* arg) {
return;
}
- // Check if object is a method without its code set and point it to the resolution trampoline.
+ // Set entry points to interpreter for methods in interpreter only mode.
if (obj->IsMethod()) {
mirror::AbstractMethod* method = obj->AsMethod();
- // Install entry point from interpreter.
- if (method->GetEntryPointFromCompiledCode() == NULL && !method->IsNative() && !method->IsProxyMethod()) {
- method->SetEntryPointFromInterpreter(interpreter::EnterInterpreterFromInterpreter);
- } else {
- method->SetEntryPointFromInterpreter(artInterpreterToQuickEntry);
- }
- if (method->GetEntryPointFromCompiledCode() == NULL) {
- method->SetEntryPointFromCompiledCode(GetResolutionTrampoline());
+ if (Runtime::Current()->GetInstrumentation()->InterpretOnly() && !method->IsNative()) {
+ method->SetEntryPointFromInterpreter(interpreter::artInterpreterToInterpreterEntry);
+ if (method != Runtime::Current()->GetResolutionMethod()) {
+ method->SetEntryPointFromCompiledCode(GetInterpreterEntryPoint());
+ }
}
}
}
@@ -1055,18 +1057,18 @@ void ClassLinker::InitFromImageCallback(mirror::Object* obj, void* arg) {
// Keep in sync with InitCallback. Anything we visit, we need to
// reinit references to when reinitializing a ClassLinker from a
// mapped image.
-void ClassLinker::VisitRoots(RootVisitor* visitor, void* arg) {
+void ClassLinker::VisitRoots(RootVisitor* visitor, void* arg, bool clean_dirty) {
visitor(class_roots_, arg);
Thread* self = Thread::Current();
{
- MutexLock mu(self, dex_lock_);
+ ReaderMutexLock mu(self, dex_lock_);
for (size_t i = 0; i < dex_caches_.size(); i++) {
visitor(dex_caches_[i], arg);
}
}
{
- MutexLock mu(self, *Locks::classlinker_classes_lock_);
+ ReaderMutexLock mu(self, *Locks::classlinker_classes_lock_);
typedef Table::const_iterator It; // TODO: C++0x auto
for (It it = classes_.begin(), end = classes_.end(); it != end; ++it) {
visitor(it->second, arg);
@@ -1077,11 +1079,13 @@ void ClassLinker::VisitRoots(RootVisitor* visitor, void* arg) {
}
visitor(array_iftable_, arg);
- is_dirty_ = false;
+ if (clean_dirty) {
+ is_dirty_ = false;
+ }
}
void ClassLinker::VisitClasses(ClassVisitor* visitor, void* arg) const {
- MutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
+ ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
typedef Table::const_iterator It; // TODO: C++0x auto
for (It it = classes_.begin(), end = classes_.end(); it != end; ++it) {
if (!visitor(it->second, arg)) {
@@ -1133,7 +1137,7 @@ ClassLinker::~ClassLinker() {
}
mirror::DexCache* ClassLinker::AllocDexCache(Thread* self, const DexFile& dex_file) {
- Heap* heap = Runtime::Current()->GetHeap();
+ gc::Heap* heap = Runtime::Current()->GetHeap();
mirror::Class* dex_cache_class = GetClassRoot(kJavaLangDexCache);
SirtRef<mirror::DexCache> dex_cache(self,
down_cast<mirror::DexCache*>(heap->AllocObject(self, dex_cache_class,
@@ -1186,7 +1190,7 @@ mirror::DexCache* ClassLinker::AllocDexCache(Thread* self, const DexFile& dex_fi
mirror::Class* ClassLinker::AllocClass(Thread* self, mirror::Class* java_lang_Class,
size_t class_size) {
DCHECK_GE(class_size, sizeof(mirror::Class));
- Heap* heap = Runtime::Current()->GetHeap();
+ gc::Heap* heap = Runtime::Current()->GetHeap();
SirtRef<mirror::Class> klass(self,
heap->AllocObject(self, java_lang_Class, class_size)->AsClass());
klass->SetPrimitiveType(Primitive::kPrimNot); // default to not being primitive
@@ -1608,14 +1612,16 @@ static void LinkCode(SirtRef<mirror::AbstractMethod>& method, const OatFile::Oat
oat_method.LinkMethod(method.get());
// Install entry point from interpreter.
- if (method->GetEntryPointFromCompiledCode() == NULL && !method->IsNative() &&
- !method->IsProxyMethod()) {
- method->SetEntryPointFromInterpreter(interpreter::EnterInterpreterFromInterpreter);
+ Runtime* runtime = Runtime::Current();
+ bool enter_interpreter = method->GetEntryPointFromCompiledCode() == NULL ||
+ (runtime->GetInstrumentation()->InterpretOnly() &&
+ !method->IsNative() && !method->IsProxyMethod());
+ if (enter_interpreter) {
+ method->SetEntryPointFromInterpreter(interpreter::artInterpreterToInterpreterEntry);
} else {
method->SetEntryPointFromInterpreter(artInterpreterToQuickEntry);
}
- Runtime* runtime = Runtime::Current();
if (method->IsAbstract()) {
method->SetEntryPointFromCompiledCode(GetAbstractMethodErrorStub());
return;
@@ -1623,7 +1629,7 @@ static void LinkCode(SirtRef<mirror::AbstractMethod>& method, const OatFile::Oat
if (method->IsStatic() && !method->IsConstructor()) {
// For static methods excluding the class initializer, install the trampoline.
- method->SetEntryPointFromCompiledCode(GetResolutionTrampoline());
+ method->SetEntryPointFromCompiledCode(GetResolutionTrampoline(runtime->GetClassLinker()));
}
if (method->IsNative()) {
@@ -1631,8 +1637,8 @@ static void LinkCode(SirtRef<mirror::AbstractMethod>& method, const OatFile::Oat
method->UnregisterNative(Thread::Current());
}
- if (method->GetEntryPointFromCompiledCode() == NULL) {
- // No code? You must mean to go into the interpreter.
+ if (enter_interpreter) {
+ // Set entry point from compiled code if there's no code or in interpreter only mode.
method->SetEntryPointFromCompiledCode(GetInterpreterEntryPoint());
}
@@ -1807,7 +1813,7 @@ void ClassLinker::AppendToBootClassPath(const DexFile& dex_file, SirtRef<mirror:
}
bool ClassLinker::IsDexFileRegisteredLocked(const DexFile& dex_file) const {
- dex_lock_.AssertHeld(Thread::Current());
+ dex_lock_.AssertSharedHeld(Thread::Current());
for (size_t i = 0; i != dex_caches_.size(); ++i) {
if (dex_caches_[i]->GetDexFile() == &dex_file) {
return true;
@@ -1817,12 +1823,12 @@ bool ClassLinker::IsDexFileRegisteredLocked(const DexFile& dex_file) const {
}
bool ClassLinker::IsDexFileRegistered(const DexFile& dex_file) const {
- MutexLock mu(Thread::Current(), dex_lock_);
+ ReaderMutexLock mu(Thread::Current(), dex_lock_);
return IsDexFileRegisteredLocked(dex_file);
}
void ClassLinker::RegisterDexFileLocked(const DexFile& dex_file, SirtRef<mirror::DexCache>& dex_cache) {
- dex_lock_.AssertHeld(Thread::Current());
+ dex_lock_.AssertExclusiveHeld(Thread::Current());
CHECK(dex_cache.get() != NULL) << dex_file.GetLocation();
CHECK(dex_cache->GetLocation()->Equals(dex_file.GetLocation()));
dex_caches_.push_back(dex_cache.get());
@@ -1833,7 +1839,7 @@ void ClassLinker::RegisterDexFileLocked(const DexFile& dex_file, SirtRef<mirror:
void ClassLinker::RegisterDexFile(const DexFile& dex_file) {
Thread* self = Thread::Current();
{
- MutexLock mu(self, dex_lock_);
+ ReaderMutexLock mu(self, dex_lock_);
if (IsDexFileRegisteredLocked(dex_file)) {
return;
}
@@ -1843,7 +1849,7 @@ void ClassLinker::RegisterDexFile(const DexFile& dex_file) {
// get to a suspend point.
SirtRef<mirror::DexCache> dex_cache(self, AllocDexCache(self, dex_file));
{
- MutexLock mu(self, dex_lock_);
+ WriterMutexLock mu(self, dex_lock_);
if (IsDexFileRegisteredLocked(dex_file)) {
return;
}
@@ -1852,12 +1858,12 @@ void ClassLinker::RegisterDexFile(const DexFile& dex_file) {
}
void ClassLinker::RegisterDexFile(const DexFile& dex_file, SirtRef<mirror::DexCache>& dex_cache) {
- MutexLock mu(Thread::Current(), dex_lock_);
+ WriterMutexLock mu(Thread::Current(), dex_lock_);
RegisterDexFileLocked(dex_file, dex_cache);
}
mirror::DexCache* ClassLinker::FindDexCache(const DexFile& dex_file) const {
- MutexLock mu(Thread::Current(), dex_lock_);
+ ReaderMutexLock mu(Thread::Current(), dex_lock_);
// Search assuming unique-ness of dex file.
for (size_t i = 0; i != dex_caches_.size(); ++i) {
mirror::DexCache* dex_cache = dex_caches_[i];
@@ -1883,7 +1889,7 @@ mirror::DexCache* ClassLinker::FindDexCache(const DexFile& dex_file) const {
}
void ClassLinker::FixupDexCaches(mirror::AbstractMethod* resolution_method) const {
- MutexLock mu(Thread::Current(), dex_lock_);
+ ReaderMutexLock mu(Thread::Current(), dex_lock_);
for (size_t i = 0; i != dex_caches_.size(); ++i) {
dex_caches_[i]->Fixup(resolution_method);
}
@@ -2017,15 +2023,16 @@ mirror::Class* ClassLinker::CreateArrayClass(const std::string& descriptor,
CHECK(array_iftable_ != NULL);
new_class->SetIfTable(array_iftable_);
- // Inherit access flags from the component type. Arrays can't be
- // used as a superclass or interface, so we want to add "final"
+ // Inherit access flags from the component type.
+ int access_flags = new_class->GetComponentType()->GetAccessFlags();
+ // Lose any implementation detail flags; in particular, arrays aren't finalizable.
+ access_flags &= kAccJavaFlagsMask;
+ // Arrays can't be used as a superclass or interface, so we want to add "abstract final"
// and remove "interface".
- //
- // Don't inherit any non-standard flags (e.g., kAccFinal)
- // from component_type. We assume that the array class does not
- // override finalize().
- new_class->SetAccessFlags(((new_class->GetComponentType()->GetAccessFlags() &
- ~kAccInterface) | kAccFinal) & kAccJavaFlagsMask);
+ access_flags |= kAccAbstract | kAccFinal;
+ access_flags &= ~kAccInterface;
+
+ new_class->SetAccessFlags(access_flags);
mirror::Class* existing = InsertClass(descriptor, new_class.get(), false);
if (existing == NULL) {
@@ -2068,7 +2075,8 @@ mirror::Class* ClassLinker::FindPrimitiveClass(char type) {
return NULL;
}
-mirror::Class* ClassLinker::InsertClass(const StringPiece& descriptor, mirror::Class* klass, bool image_class) {
+mirror::Class* ClassLinker::InsertClass(const StringPiece& descriptor, mirror::Class* klass,
+ bool image_class) {
if (VLOG_IS_ON(class_linker)) {
mirror::DexCache* dex_cache = klass->GetDexCache();
std::string source;
@@ -2079,9 +2087,10 @@ mirror::Class* ClassLinker::InsertClass(const StringPiece& descriptor, mirror::C
LOG(INFO) << "Loaded class " << descriptor << source;
}
size_t hash = StringPieceHash()(descriptor);
- MutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
+ WriterMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
Table& classes = image_class ? image_classes_ : classes_;
- mirror::Class* existing = LookupClassLocked(descriptor.data(), klass->GetClassLoader(), hash, classes);
+ mirror::Class* existing =
+ LookupClassLocked(descriptor.data(), klass->GetClassLoader(), hash, classes);
#ifndef NDEBUG
// Check we don't have the class in the other table in error
Table& other_classes = image_class ? classes_ : image_classes_;
@@ -2090,6 +2099,7 @@ mirror::Class* ClassLinker::InsertClass(const StringPiece& descriptor, mirror::C
if (existing != NULL) {
return existing;
}
+ Runtime::Current()->GetHeap()->VerifyObject(klass);
classes.insert(std::make_pair(hash, klass));
Dirty();
return NULL;
@@ -2097,7 +2107,7 @@ mirror::Class* ClassLinker::InsertClass(const StringPiece& descriptor, mirror::C
bool ClassLinker::RemoveClass(const char* descriptor, const mirror::ClassLoader* class_loader) {
size_t hash = Hash(descriptor);
- MutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
+ WriterMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
typedef Table::iterator It; // TODO: C++0x auto
// TODO: determine if its better to search classes_ or image_classes_ first
ClassHelper kh;
@@ -2125,7 +2135,7 @@ bool ClassLinker::RemoveClass(const char* descriptor, const mirror::ClassLoader*
mirror::Class* ClassLinker::LookupClass(const char* descriptor,
const mirror::ClassLoader* class_loader) {
size_t hash = Hash(descriptor);
- MutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
+ ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
// TODO: determine if its better to search classes_ or image_classes_ first
mirror::Class* klass = NULL;
// Use image class only if the class_loader is null.
@@ -2165,7 +2175,7 @@ mirror::Class* ClassLinker::LookupClassLocked(const char* descriptor,
void ClassLinker::LookupClasses(const char* descriptor, std::vector<mirror::Class*>& classes) {
classes.clear();
size_t hash = Hash(descriptor);
- MutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
+ ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
typedef Table::const_iterator It; // TODO: C++0x auto
// TODO: determine if its better to search classes_ or image_classes_ first
ClassHelper kh(NULL, this);
@@ -2243,7 +2253,6 @@ void ClassLinker::VerifyClass(mirror::Class* klass) {
const DexFile& dex_file = *klass->GetDexCache()->GetDexFile();
mirror::Class::Status oat_file_class_status(mirror::Class::kStatusNotReady);
bool preverified = VerifyClassUsingOatFile(dex_file, klass, oat_file_class_status);
- verifier::MethodVerifier::FailureKind verifier_failure = verifier::MethodVerifier::kNoFailure;
if (oat_file_class_status == mirror::Class::kStatusError) {
LOG(WARNING) << "Skipping runtime verification of erroneous class " << PrettyDescriptor(klass)
<< " in " << klass->GetDexCache()->GetLocation()->ToModifiedUtf8();
@@ -2252,9 +2261,11 @@ void ClassLinker::VerifyClass(mirror::Class* klass) {
klass->SetStatus(mirror::Class::kStatusError);
return;
}
+ verifier::MethodVerifier::FailureKind verifier_failure = verifier::MethodVerifier::kNoFailure;
std::string error_msg;
if (!preverified) {
- verifier_failure = verifier::MethodVerifier::VerifyClass(klass, error_msg, Runtime::Current()->IsCompiler());
+ verifier_failure = verifier::MethodVerifier::VerifyClass(klass, error_msg,
+ Runtime::Current()->IsCompiler());
}
if (preverified || verifier_failure != verifier::MethodVerifier::kHardFailure) {
if (!preverified && verifier_failure != verifier::MethodVerifier::kNoFailure) {
@@ -2286,6 +2297,15 @@ void ClassLinker::VerifyClass(mirror::Class* klass) {
ThrowVerifyError(klass, "%s", error_msg.c_str());
klass->SetStatus(mirror::Class::kStatusError);
}
+ if (preverified || verifier_failure == verifier::MethodVerifier::kNoFailure) {
+ // Class is verified so we don't need to do any access check in its methods.
+ // Let the interpreter know it by setting the kAccPreverified flag onto each
+ // method.
+ // Note: we're going here during compilation and at runtime. When we set the
+ // kAccPreverified flag when compiling image classes, the flag is recorded
+ // in the image and is set when loading the image.
+ klass->SetPreverifiedFlagOnAllMethods();
+ }
}
bool ClassLinker::VerifyClassUsingOatFile(const DexFile& dex_file, mirror::Class* klass,
@@ -2499,7 +2519,7 @@ mirror::AbstractMethod* ClassLinker::FindMethodForProxy(const mirror::Class* pro
mirror::DexCache* dex_cache = NULL;
{
mirror::ObjectArray<mirror::Class>* resolved_types = proxy_method->GetDexCacheResolvedTypes();
- MutexLock mu(Thread::Current(), dex_lock_);
+ ReaderMutexLock mu(Thread::Current(), dex_lock_);
for (size_t i = 0; i != dex_caches_.size(); ++i) {
if (dex_caches_[i]->GetResolvedTypes() == resolved_types) {
dex_cache = dex_caches_[i];
@@ -3880,7 +3900,7 @@ void ClassLinker::DumpAllClasses(int flags) const {
// lock held, because it might need to resolve a field's type, which would try to take the lock.
std::vector<mirror::Class*> all_classes;
{
- MutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
+ ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
typedef Table::const_iterator It; // TODO: C++0x auto
for (It it = classes_.begin(), end = classes_.end(); it != end; ++it) {
all_classes.push_back(it->second);
@@ -3896,13 +3916,13 @@ void ClassLinker::DumpAllClasses(int flags) const {
}
void ClassLinker::DumpForSigQuit(std::ostream& os) const {
- MutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
+ ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
os << "Loaded classes: " << image_classes_.size() << " image classes; "
<< classes_.size() << " allocated classes\n";
}
size_t ClassLinker::NumLoadedClasses() const {
- MutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
+ ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
return classes_.size() + image_classes_.size();
}
diff --git a/src/class_linker.h b/src/class_linker.h
index d41373c7d7..df336724fa 100644
--- a/src/class_linker.h
+++ b/src/class_linker.h
@@ -29,6 +29,11 @@
#include "oat_file.h"
namespace art {
+namespace gc {
+namespace space {
+ class ImageSpace;
+} // namespace space
+} // namespace gc
namespace mirror {
class ClassLoader;
class DexCache;
@@ -37,7 +42,7 @@ namespace mirror {
template<class T> class ObjectArray;
class StackTraceElement;
} // namespace mirror
-class ImageSpace;
+
class InternTable;
class ObjectLock;
template<class T> class SirtRef;
@@ -219,7 +224,7 @@ class ClassLinker {
void VisitClassesWithoutClassesLock(ClassVisitor* visitor, void* arg) const
LOCKS_EXCLUDED(Locks::classlinker_classes_lock_);
- void VisitRoots(RootVisitor* visitor, void* arg)
+ void VisitRoots(RootVisitor* visitor, void* arg, bool clean_dirty)
LOCKS_EXCLUDED(Locks::classlinker_classes_lock_, dex_lock_);
mirror::DexCache* FindDexCache(const DexFile& dex_file) const
@@ -240,7 +245,7 @@ class ClassLinker {
LOCKS_EXCLUDED(dex_lock_);
const OatFile* FindOatFileFromOatLocationLocked(const std::string& location)
- EXCLUSIVE_LOCKS_REQUIRED(dex_lock_);
+ SHARED_LOCKS_REQUIRED(dex_lock_);
// Finds the oat file for a dex location, generating the oat file if
// it is missing or out of date. Returns the DexFile from within the
@@ -334,6 +339,14 @@ class ClassLinker {
is_dirty_ = true;
}
+ const void* GetPortableResolutionTrampoline() const {
+ return portable_resolution_trampoline_;
+ }
+
+ const void* GetQuickResolutionTrampoline() const {
+ return quick_resolution_trampoline_;
+ }
+
private:
explicit ClassLinker(InternTable*);
@@ -346,7 +359,7 @@ class ClassLinker {
// Initialize class linker from one or more images.
void InitFromImage() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- OatFile* OpenOat(const ImageSpace* space)
+ OatFile* OpenOat(const gc::space::ImageSpace* space)
LOCKS_EXCLUDED(dex_lock_)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
static void InitFromImageCallback(mirror::Object* obj, void* arg)
@@ -420,7 +433,7 @@ class ClassLinker {
void RegisterDexFileLocked(const DexFile& dex_file, SirtRef<mirror::DexCache>& dex_cache)
EXCLUSIVE_LOCKS_REQUIRED(dex_lock_)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- bool IsDexFileRegisteredLocked(const DexFile& dex_file) const EXCLUSIVE_LOCKS_REQUIRED(dex_lock_);
+ bool IsDexFileRegisteredLocked(const DexFile& dex_file) const SHARED_LOCKS_REQUIRED(dex_lock_);
void RegisterOatFileLocked(const OatFile& oat_file) EXCLUSIVE_LOCKS_REQUIRED(dex_lock_)
EXCLUSIVE_LOCKS_REQUIRED(dex_lock_);
@@ -489,10 +502,15 @@ class ClassLinker {
LOCKS_EXCLUDED(dex_lock_)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
const OatFile* FindOpenedOatFileFromDexLocation(const std::string& dex_location)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_, dex_lock_);
+ const OatFile* FindOpenedOatFileFromOatLocation(const std::string& oat_location)
+ SHARED_LOCKS_REQUIRED(dex_lock_);
+ const DexFile* FindDexFileInOatLocation(const std::string& dex_location,
+ uint32_t dex_location_checksum,
+ const std::string& oat_location)
EXCLUSIVE_LOCKS_REQUIRED(dex_lock_)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- const OatFile* FindOpenedOatFileFromOatLocation(const std::string& oat_location)
- EXCLUSIVE_LOCKS_REQUIRED(dex_lock_);
+
const DexFile* VerifyAndOpenDexFileFromOatFile(const OatFile* oat_file,
const std::string& dex_location,
uint32_t dex_location_checksum)
@@ -508,7 +526,7 @@ class ClassLinker {
std::vector<const DexFile*> boot_class_path_;
- mutable Mutex dex_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
+ mutable ReaderWriterMutex dex_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
std::vector<mirror::DexCache*> dex_caches_ GUARDED_BY(dex_lock_);
std::vector<const OatFile*> oat_files_ GUARDED_BY(dex_lock_);
@@ -522,8 +540,7 @@ class ClassLinker {
mirror::Class* LookupClassLocked(const char* descriptor, const mirror::ClassLoader* class_loader,
size_t hash, const Table& classes)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
- EXCLUSIVE_LOCKS_REQUIRED(Locks::classlinker_classes_lock_);
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_, Locks::classlinker_classes_lock_);
// indexes into class_roots_.
// needs to be kept in sync with class_roots_descriptors_.
@@ -595,6 +612,9 @@ class ClassLinker {
InternTable* intern_table_;
+ const void* portable_resolution_trampoline_;
+ const void* quick_resolution_trampoline_;
+
friend class CommonTest;
friend class ImageWriter; // for GetClassRoots
friend class ObjectTest;
diff --git a/src/class_linker_test.cc b/src/class_linker_test.cc
index 73bdc613ab..e5844b0038 100644
--- a/src/class_linker_test.cc
+++ b/src/class_linker_test.cc
@@ -22,7 +22,7 @@
#include "class_linker-inl.h"
#include "common_test.h"
#include "dex_file.h"
-#include "heap.h"
+#include "gc/heap.h"
#include "mirror/class-inl.h"
#include "mirror/dex_cache.h"
#include "mirror/field-inl.h"
@@ -90,6 +90,7 @@ class ClassLinkerTest : public CommonTest {
EXPECT_TRUE(primitive->GetVTable() == NULL);
EXPECT_EQ(0, primitive->GetIfTableCount());
EXPECT_TRUE(primitive->GetIfTable() == NULL);
+ EXPECT_EQ(kAccPublic | kAccFinal | kAccAbstract, primitive->GetAccessFlags());
}
void AssertArrayClass(const std::string& array_descriptor,
@@ -100,6 +101,7 @@ class ClassLinkerTest : public CommonTest {
ClassHelper array_component_ch(array->GetComponentType());
EXPECT_STREQ(component_type.c_str(), array_component_ch.GetDescriptor());
EXPECT_EQ(class_loader, array->GetClassLoader());
+ EXPECT_EQ(kAccFinal | kAccAbstract, (array->GetAccessFlags() & (kAccFinal | kAccAbstract)));
AssertArrayClass(array_descriptor, array);
}
@@ -331,7 +333,7 @@ class ClassLinkerTest : public CommonTest {
const char* descriptor = dex->GetTypeDescriptor(type_id);
AssertDexFileClass(class_loader, descriptor);
}
- class_linker_->VisitRoots(TestRootVisitor, NULL);
+ class_linker_->VisitRoots(TestRootVisitor, NULL, false);
// Verify the dex cache has resolution methods in all resolved method slots
DexCache* dex_cache = class_linker_->FindDexCache(*dex);
ObjectArray<AbstractMethod>* resolved_methods = dex_cache->GetResolvedMethods();
diff --git a/src/common_test.h b/src/common_test.h
index 8d8ad5eb52..11bd4f0957 100644
--- a/src/common_test.h
+++ b/src/common_test.h
@@ -28,8 +28,8 @@
#include "class_linker.h"
#include "compiler/driver/compiler_driver.h"
#include "dex_file-inl.h"
+#include "gc/heap.h"
#include "gtest/gtest.h"
-#include "heap.h"
#include "instruction_set.h"
#include "mirror/class_loader.h"
#include "oat_file.h"
@@ -296,8 +296,8 @@ class CommonTest : public testing::Test {
boot_class_path_.push_back(java_lang_dex_file_);
boot_class_path_.push_back(conscrypt_file_);
- std::string min_heap_string(StringPrintf("-Xms%zdm", Heap::kDefaultInitialSize / MB));
- std::string max_heap_string(StringPrintf("-Xmx%zdm", Heap::kDefaultMaximumSize / MB));
+ std::string min_heap_string(StringPrintf("-Xms%zdm", gc::Heap::kDefaultInitialSize / MB));
+ std::string max_heap_string(StringPrintf("-Xmx%zdm", gc::Heap::kDefaultMaximumSize / MB));
Runtime::Options options;
options.push_back(std::make_pair("compiler", reinterpret_cast<void*>(NULL)));
@@ -313,47 +313,50 @@ class CommonTest : public testing::Test {
// Runtime::Create acquired the mutator_lock_ that is normally given away when we Runtime::Start,
// give it away now and then switch to a more managable ScopedObjectAccess.
Thread::Current()->TransitionFromRunnableToSuspended(kNative);
- // Whilst we're in native take the opportunity to initialize well known classes.
- WellKnownClasses::InitClasses(Thread::Current()->GetJniEnv());
- ScopedObjectAccess soa(Thread::Current());
- ASSERT_TRUE(runtime_.get() != NULL);
- class_linker_ = runtime_->GetClassLinker();
+ {
+ ScopedObjectAccess soa(Thread::Current());
+ ASSERT_TRUE(runtime_.get() != NULL);
+ class_linker_ = runtime_->GetClassLinker();
- InstructionSet instruction_set = kNone;
+ InstructionSet instruction_set = kNone;
#if defined(__arm__)
- instruction_set = kThumb2;
+ instruction_set = kThumb2;
#elif defined(__mips__)
- instruction_set = kMips;
+ instruction_set = kMips;
#elif defined(__i386__)
- instruction_set = kX86;
+ instruction_set = kX86;
#endif
- // TODO: make selectable
+ // TODO: make selectable
#if defined(ART_USE_PORTABLE_COMPILER)
- CompilerBackend compiler_backend = kPortable;
+ CompilerBackend compiler_backend = kPortable;
#else
- CompilerBackend compiler_backend = kQuick;
+ CompilerBackend compiler_backend = kQuick;
#endif
- if (!runtime_->HasResolutionMethod()) {
- runtime_->SetResolutionMethod(runtime_->CreateResolutionMethod());
- }
- for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) {
- Runtime::CalleeSaveType type = Runtime::CalleeSaveType(i);
- if (!runtime_->HasCalleeSaveMethod(type)) {
- runtime_->SetCalleeSaveMethod(
- runtime_->CreateCalleeSaveMethod(instruction_set, type), type);
+ if (!runtime_->HasResolutionMethod()) {
+ runtime_->SetResolutionMethod(runtime_->CreateResolutionMethod());
+ }
+ for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) {
+ Runtime::CalleeSaveType type = Runtime::CalleeSaveType(i);
+ if (!runtime_->HasCalleeSaveMethod(type)) {
+ runtime_->SetCalleeSaveMethod(
+ runtime_->CreateCalleeSaveMethod(instruction_set, type), type);
+ }
}
+ class_linker_->FixupDexCaches(runtime_->GetResolutionMethod());
+ compiler_driver_.reset(new CompilerDriver(compiler_backend, instruction_set,
+ true, new CompilerDriver::DescriptorSet,
+ 2, false, true, true));
}
- class_linker_->FixupDexCaches(runtime_->GetResolutionMethod());
- image_classes_.reset(new std::set<std::string>);
- compiler_driver_.reset(new CompilerDriver(compiler_backend, instruction_set, true, 2, false,
- image_classes_.get(), true, true));
+ // We typically don't generate an image in unit tests, disable this optimization by default.
+ compiler_driver_->SetSupportBootImageFixup(false);
+ // We're back in native, take the opportunity to initialize well known classes.
+ WellKnownClasses::InitClasses(Thread::Current()->GetJniEnv());
// Create the heap thread pool so that the GC runs in parallel for tests. Normally, the thread
// pool is created by the runtime.
runtime_->GetHeap()->CreateThreadPool();
-
runtime_->GetHeap()->VerifyHeap(); // Check for heap corruption before the test
}
@@ -389,7 +392,6 @@ class CommonTest : public testing::Test {
(*icu_cleanup_fn)();
compiler_driver_.reset();
- image_classes_.reset();
STLDeleteElements(&opened_dex_files_);
Runtime::Current()->GetHeap()->VerifyHeap(); // Check for heap corruption after the test
@@ -522,7 +524,6 @@ class CommonTest : public testing::Test {
// Owned by the runtime
ClassLinker* class_linker_;
UniquePtr<CompilerDriver> compiler_driver_;
- UniquePtr<std::set<std::string> > image_classes_;
private:
std::vector<const DexFile*> opened_dex_files_;
diff --git a/src/common_throws.cc b/src/common_throws.cc
index dc3627a0b2..66e512eef3 100644
--- a/src/common_throws.cc
+++ b/src/common_throws.cc
@@ -27,6 +27,7 @@
#include "mirror/object_array-inl.h"
#include "object_utils.h"
#include "thread.h"
+#include "verifier/method_verifier.h"
#include <sstream>
@@ -67,7 +68,7 @@ static void ThrowException(const ThrowLocation* throw_location, const char* exce
// ArithmeticException
-void ThrowArithmeticExceptionDivideByZero(Thread* self) {
+void ThrowArithmeticExceptionDivideByZero() {
ThrowException(NULL, "Ljava/lang/ArithmeticException;", NULL, "divide by zero");
}
@@ -283,16 +284,34 @@ void ThrowNullPointerExceptionForFieldAccess(const ThrowLocation& throw_location
ThrowException(&throw_location, "Ljava/lang/NullPointerException;", NULL, msg.str().c_str());
}
-void ThrowNullPointerExceptionForMethodAccess(const ThrowLocation& throw_location, uint32_t method_idx,
- InvokeType type) {
- mirror::DexCache* dex_cache = throw_location.GetMethod()->GetDeclaringClass()->GetDexCache();
- const DexFile& dex_file = *dex_cache->GetDexFile();
+static void ThrowNullPointerExceptionForMethodAccessImpl(const ThrowLocation& throw_location,
+ uint32_t method_idx,
+ const DexFile& dex_file,
+ InvokeType type)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
std::ostringstream msg;
msg << "Attempt to invoke " << type << " method '"
<< PrettyMethod(method_idx, dex_file, true) << "' on a null object reference";
ThrowException(&throw_location, "Ljava/lang/NullPointerException;", NULL, msg.str().c_str());
}
+void ThrowNullPointerExceptionForMethodAccess(const ThrowLocation& throw_location, uint32_t method_idx,
+ InvokeType type) {
+ mirror::DexCache* dex_cache = throw_location.GetMethod()->GetDeclaringClass()->GetDexCache();
+ const DexFile& dex_file = *dex_cache->GetDexFile();
+ ThrowNullPointerExceptionForMethodAccessImpl(throw_location, method_idx,
+ dex_file, type);
+}
+
+void ThrowNullPointerExceptionForMethodAccess(const ThrowLocation& throw_location,
+ mirror::AbstractMethod* method,
+ InvokeType type) {
+ mirror::DexCache* dex_cache = method->GetDeclaringClass()->GetDexCache();
+ const DexFile& dex_file = *dex_cache->GetDexFile();
+ ThrowNullPointerExceptionForMethodAccessImpl(throw_location, method->GetDexMethodIndex(),
+ dex_file, type);
+}
+
void ThrowNullPointerExceptionFromDexPC(const ThrowLocation& throw_location) {
const DexFile::CodeItem* code = MethodHelper(throw_location.GetMethod()).GetCodeItem();
uint32_t throw_dex_pc = throw_location.GetDexPc();
@@ -317,6 +336,23 @@ void ThrowNullPointerExceptionFromDexPC(const ThrowLocation& throw_location) {
case Instruction::INVOKE_INTERFACE_RANGE:
ThrowNullPointerExceptionForMethodAccess(throw_location, instr->VRegB_3rc(), kInterface);
break;
+ case Instruction::INVOKE_VIRTUAL_QUICK:
+ case Instruction::INVOKE_VIRTUAL_RANGE_QUICK: {
+ // Since we replaced the method index, we ask the verifier to tell us which
+ // method is invoked at this location.
+ mirror::AbstractMethod* method =
+ verifier::MethodVerifier::FindInvokedMethodAtDexPc(throw_location.GetMethod(),
+ throw_location.GetDexPc());
+ if (method != NULL) {
+ // NPE with precise message.
+ ThrowNullPointerExceptionForMethodAccess(throw_location, method, kVirtual);
+ } else {
+ // NPE with imprecise message.
+ ThrowNullPointerException(&throw_location,
+ "Attempt to invoke a virtual method on a null object reference");
+ }
+ break;
+ }
case Instruction::IGET:
case Instruction::IGET_WIDE:
case Instruction::IGET_OBJECT:
@@ -330,6 +366,24 @@ void ThrowNullPointerExceptionFromDexPC(const ThrowLocation& throw_location) {
ThrowNullPointerExceptionForFieldAccess(throw_location, field, true /* read */);
break;
}
+ case Instruction::IGET_QUICK:
+ case Instruction::IGET_WIDE_QUICK:
+ case Instruction::IGET_OBJECT_QUICK: {
+ // Since we replaced the field index, we ask the verifier to tell us which
+ // field is accessed at this location.
+ mirror::Field* field =
+ verifier::MethodVerifier::FindAccessedFieldAtDexPc(throw_location.GetMethod(),
+ throw_location.GetDexPc());
+ if (field != NULL) {
+ // NPE with precise message.
+ ThrowNullPointerExceptionForFieldAccess(throw_location, field, true /* read */);
+ } else {
+ // NPE with imprecise message.
+ ThrowNullPointerException(&throw_location,
+ "Attempt to read from a field on a null object reference");
+ }
+ break;
+ }
case Instruction::IPUT:
case Instruction::IPUT_WIDE:
case Instruction::IPUT_OBJECT:
@@ -343,6 +397,24 @@ void ThrowNullPointerExceptionFromDexPC(const ThrowLocation& throw_location) {
ThrowNullPointerExceptionForFieldAccess(throw_location, field, false /* write */);
break;
}
+ case Instruction::IPUT_QUICK:
+ case Instruction::IPUT_WIDE_QUICK:
+ case Instruction::IPUT_OBJECT_QUICK: {
+ // Since we replaced the field index, we ask the verifier to tell us which
+ // field is accessed at this location.
+ mirror::Field* field =
+ verifier::MethodVerifier::FindAccessedFieldAtDexPc(throw_location.GetMethod(),
+ throw_location.GetDexPc());
+ if (field != NULL) {
+ // NPE with precise message.
+ ThrowNullPointerExceptionForFieldAccess(throw_location, field, false /* write */);
+ } else {
+ // NPE with imprecise message.
+ ThrowNullPointerException(&throw_location,
+ "Attempt to write to a field on a null object reference");
+ }
+ break;
+ }
case Instruction::AGET:
case Instruction::AGET_WIDE:
case Instruction::AGET_OBJECT:
diff --git a/src/common_throws.h b/src/common_throws.h
index 5555435051..fbaf4c199f 100644
--- a/src/common_throws.h
+++ b/src/common_throws.h
@@ -32,7 +32,7 @@ class ThrowLocation;
// ArithmeticException
-void ThrowArithmeticExceptionDivideByZero(Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+void ThrowArithmeticExceptionDivideByZero() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// ArrayIndexOutOfBoundsException
@@ -153,6 +153,11 @@ void ThrowNullPointerExceptionForMethodAccess(const ThrowLocation& throw_locatio
InvokeType type)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+void ThrowNullPointerExceptionForMethodAccess(const ThrowLocation& throw_location,
+ mirror::AbstractMethod* method,
+ InvokeType type)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
void ThrowNullPointerExceptionFromDexPC(const ThrowLocation& throw_location)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/src/compiler/dex/arena_bit_vector.cc b/src/compiler/dex/arena_bit_vector.cc
index 6f664e5565..1fbf7740ac 100644
--- a/src/compiler/dex/arena_bit_vector.cc
+++ b/src/compiler/dex/arena_bit_vector.cc
@@ -113,18 +113,6 @@ void ArenaBitVector::Union(const ArenaBitVector* src) {
}
}
-// Are we equal to another bit vector? Note: expandability attributes must also match.
-bool ArenaBitVector::Equal(const ArenaBitVector* src) {
- if (storage_size_ != src->GetStorageSize() ||
- expandable_ != src->IsExpandable())
- return false;
-
- for (unsigned int idx = 0; idx < storage_size_; idx++) {
- if (storage_[idx] != src->GetRawStorageWord(idx)) return false;
- }
- return true;
-}
-
// Count the number of bits that are set.
int ArenaBitVector::NumSetBits()
{
@@ -136,43 +124,6 @@ int ArenaBitVector::NumSetBits()
return count;
}
-// Return the position of the next set bit. -1 means end-of-element reached.
-// TUNING: Hot function.
-int ArenaBitVector::Iterator::Next()
-{
- // Did anything obviously change since we started?
- DCHECK_EQ(bit_size_, p_bits_->GetStorageSize() * sizeof(uint32_t) * 8);
- DCHECK_EQ(bit_storage_, p_bits_->GetRawStorage());
-
- if (bit_index_ >= bit_size_) return -1;
-
- uint32_t word_index = bit_index_ >> 5;
- uint32_t end_word_index = bit_size_ >> 5;
- uint32_t word = bit_storage_[word_index++];
-
- // Mask out any bits in the first word we've already considered.
- word &= ~((1 << (bit_index_ & 0x1f))-1);
-
- for (; word_index <= end_word_index;) {
- uint32_t bit_pos = bit_index_ & 0x1f;
- if (word == 0) {
- bit_index_ += (32 - bit_pos);
- word = bit_storage_[word_index++];
- continue;
- }
- for (; bit_pos < 32; bit_pos++) {
- if (word & (1 << bit_pos)) {
- bit_index_++;
- return bit_index_ - 1;
- }
- bit_index_++;
- }
- word = bit_storage_[word_index++];
- }
- bit_index_ = bit_size_;
- return -1;
-}
-
/*
* Mark specified number of bits as "set". Cannot set all bits like ClearAll
* since there might be unused bits - setting those to one will confuse the
diff --git a/src/compiler/dex/arena_bit_vector.h b/src/compiler/dex/arena_bit_vector.h
index f5c471c5d3..a950e82498 100644
--- a/src/compiler/dex/arena_bit_vector.h
+++ b/src/compiler/dex/arena_bit_vector.h
@@ -39,7 +39,33 @@ class ArenaBitVector {
bit_index_(0),
bit_size_(p_bits_->storage_size_ * sizeof(uint32_t) * 8) {};
- int Next(); // Returns -1 when no next.
+ // Return the position of the next set bit. -1 means end-of-element reached.
+ int Next() {
+ // Did anything obviously change since we started?
+ DCHECK_EQ(bit_size_, p_bits_->GetStorageSize() * sizeof(uint32_t) * 8);
+ DCHECK_EQ(bit_storage_, p_bits_->GetRawStorage());
+
+ if (bit_index_ >= bit_size_) return -1;
+
+ uint32_t word_index = bit_index_ / 32;
+ uint32_t word = bit_storage_[word_index];
+ // Mask out any bits in the first word we've already considered.
+ word >>= bit_index_ & 0x1f;
+ if (word == 0) {
+ bit_index_ &= ~0x1f;
+ do {
+ word_index++;
+ if ((word_index * 32) >= bit_size_) {
+ bit_index_ = bit_size_;
+ return -1;
+ }
+ word = bit_storage_[word_index];
+ bit_index_ += 32;
+ } while (word == 0);
+ }
+ bit_index_ += CTZ(word) + 1;
+ return bit_index_ - 1;
+ }
static void* operator new(size_t size, ArenaAllocator* arena) {
return arena->NewMem(sizeof(ArenaBitVector::Iterator), true,
@@ -73,13 +99,19 @@ class ArenaBitVector {
void Copy(ArenaBitVector* src);
void Intersect(const ArenaBitVector* src2);
void Union(const ArenaBitVector* src);
- bool Equal(const ArenaBitVector* src);
+ // Are we equal to another bit vector? Note: expandability attributes must also match.
+ bool Equal(const ArenaBitVector* src) {
+ return (storage_size_ == src->GetStorageSize()) &&
+ (expandable_ == src->IsExpandable()) &&
+ (memcmp(storage_, src->GetRawStorage(), storage_size_ * 4) == 0);
+ }
int NumSetBits();
uint32_t GetStorageSize() const { return storage_size_; }
bool IsExpandable() const { return expandable_; }
uint32_t GetRawStorageWord(size_t idx) const { return storage_[idx]; }
uint32_t* GetRawStorage() { return storage_; }
+ const uint32_t* GetRawStorage() const { return storage_; }
private:
ArenaAllocator* const arena_;
diff --git a/src/compiler/dex/dataflow_iterator-inl.h b/src/compiler/dex/dataflow_iterator-inl.h
new file mode 100644
index 0000000000..b20004decc
--- /dev/null
+++ b/src/compiler/dex/dataflow_iterator-inl.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_SRC_COMPILER_DEX_DATAFLOW_ITERATOR_INL_H_
+#define ART_SRC_COMPILER_DEX_DATAFLOW_ITERATOR_INL_H_
+
+#include "dataflow_iterator.h"
+
+namespace art {
+
+inline BasicBlock* DataflowIterator::NextBody(bool had_change) {
+ changed_ |= had_change;
+ BasicBlock* res = NULL;
+ if (reverse_) {
+ if (is_iterative_ && changed_ && (idx_ < 0)) {
+ idx_ = start_idx_;
+ changed_ = false;
+ }
+ if (idx_ >= 0) {
+ int bb_id = block_id_list_->Get(idx_--);
+ res = mir_graph_->GetBasicBlock(bb_id);
+ }
+ } else {
+ if (is_iterative_ && changed_ && (idx_ >= end_idx_)) {
+ idx_ = start_idx_;
+ changed_ = false;
+ }
+ if (idx_ < end_idx_) {
+ int bb_id = block_id_list_->Get(idx_++);
+ res = mir_graph_->GetBasicBlock(bb_id);
+ }
+ }
+ return res;
+}
+
+// AllNodes uses the existing GrowableArray iterator, so use different NextBody().
+inline BasicBlock* AllNodesIterator::NextBody(bool had_change) {
+ changed_ |= had_change;
+ BasicBlock* res = NULL;
+ bool keep_looking = true;
+ while (keep_looking) {
+ res = all_nodes_iterator_->Next();
+ if (is_iterative_ && changed_ && (res == NULL)) {
+ all_nodes_iterator_->Reset();
+ changed_ = false;
+ } else if ((res == NULL) || (!res->hidden)) {
+ keep_looking = false;
+ }
+ }
+ return res;
+}
+
+} // namespace art
+
+#endif // ART_SRC_COMPILER_DEX_DATAFLOW_ITERATOR_INL_H_
diff --git a/src/compiler/dex/dataflow_iterator.cc b/src/compiler/dex/dataflow_iterator.cc
deleted file mode 100644
index bb5b969925..0000000000
--- a/src/compiler/dex/dataflow_iterator.cc
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "dataflow_iterator.h"
-
-namespace art {
-
- BasicBlock* DataflowIterator::NextBody(bool had_change) {
- changed_ |= had_change;
- BasicBlock* res = NULL;
- if (reverse_) {
- if (is_iterative_ && changed_ && (idx_ < 0)) {
- idx_ = start_idx_;
- changed_ = false;
- }
- if (idx_ >= 0) {
- int bb_id = block_id_list_->Get(idx_--);
- res = mir_graph_->GetBasicBlock(bb_id);
- }
- } else {
- if (is_iterative_ && changed_ && (idx_ >= end_idx_)) {
- idx_ = start_idx_;
- changed_ = false;
- }
- if (idx_ < end_idx_) {
- int bb_id = block_id_list_->Get(idx_++);
- res = mir_graph_->GetBasicBlock(bb_id);
- }
- }
- return res;
- }
-
- // AllNodes uses the existing GrowableArray iterator, so use different NextBody().
- BasicBlock* AllNodesIterator::NextBody(bool had_change) {
- changed_ |= had_change;
- BasicBlock* res = NULL;
- bool keep_looking = true;
- while (keep_looking) {
- res = all_nodes_iterator_->Next();
- if (is_iterative_ && changed_ && (res == NULL)) {
- all_nodes_iterator_->Reset();
- changed_ = false;
- } else if ((res == NULL) || (!res->hidden)) {
- keep_looking = false;
- }
- }
- return res;
- }
-
-} // namespace art
diff --git a/src/compiler/dex/dataflow_iterator.h b/src/compiler/dex/dataflow_iterator.h
index a4b38bd80f..12cbf9cadf 100644
--- a/src/compiler/dex/dataflow_iterator.h
+++ b/src/compiler/dex/dataflow_iterator.h
@@ -71,7 +71,7 @@ namespace art {
idx_(0),
changed_(false) {}
- virtual BasicBlock* NextBody(bool had_change);
+ virtual BasicBlock* NextBody(bool had_change) ALWAYS_INLINE;
MIRGraph* const mir_graph_;
const bool is_iterative_;
@@ -86,7 +86,6 @@ namespace art {
class ReachableNodesIterator : public DataflowIterator {
public:
-
ReachableNodesIterator(MIRGraph* mir_graph, bool is_iterative)
: DataflowIterator(mir_graph, is_iterative, 0,
mir_graph->GetNumReachableBlocks(), false) {
@@ -97,7 +96,6 @@ namespace art {
class PreOrderDfsIterator : public DataflowIterator {
public:
-
PreOrderDfsIterator(MIRGraph* mir_graph, bool is_iterative)
: DataflowIterator(mir_graph, is_iterative, 0,
mir_graph->GetNumReachableBlocks(), false) {
@@ -119,7 +117,6 @@ namespace art {
class ReversePostOrderDfsIterator : public DataflowIterator {
public:
-
ReversePostOrderDfsIterator(MIRGraph* mir_graph, bool is_iterative)
: DataflowIterator(mir_graph, is_iterative,
mir_graph->GetNumReachableBlocks() -1, 0, true) {
@@ -130,7 +127,6 @@ namespace art {
class PostOrderDOMIterator : public DataflowIterator {
public:
-
PostOrderDOMIterator(MIRGraph* mir_graph, bool is_iterative)
: DataflowIterator(mir_graph, is_iterative, 0,
mir_graph->GetNumReachableBlocks(), false) {
@@ -141,18 +137,17 @@ namespace art {
class AllNodesIterator : public DataflowIterator {
public:
-
AllNodesIterator(MIRGraph* mir_graph, bool is_iterative)
: DataflowIterator(mir_graph, is_iterative, 0, 0, false) {
all_nodes_iterator_ =
new (mir_graph->GetArena()) GrowableArray<BasicBlock*>::Iterator (mir_graph->GetBlockList());
}
- virtual void Reset() {
+ void Reset() {
all_nodes_iterator_->Reset();
}
- virtual BasicBlock* NextBody(bool had_change);
+ BasicBlock* NextBody(bool had_change) ALWAYS_INLINE;
private:
GrowableArray<BasicBlock*>::Iterator* all_nodes_iterator_;
diff --git a/src/compiler/dex/dex_to_dex_compiler.cc b/src/compiler/dex/dex_to_dex_compiler.cc
new file mode 100644
index 0000000000..afb29f4163
--- /dev/null
+++ b/src/compiler/dex/dex_to_dex_compiler.cc
@@ -0,0 +1,258 @@
+/*
+ * Copyright (C) 2011 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 "base/logging.h"
+#include "base/mutex.h"
+#include "compiler/driver/compiler_driver.h"
+#include "compiler/driver/dex_compilation_unit.h"
+#include "dex_file-inl.h"
+#include "dex_instruction-inl.h"
+#include "mirror/abstract_method-inl.h"
+#include "mirror/class-inl.h"
+#include "mirror/dex_cache.h"
+#include "mirror/field-inl.h"
+
+namespace art {
+namespace optimizer {
+
+// Controls quickening activation.
+const bool kEnableQuickening = true;
+// Controls logging.
+const bool kEnableLogging = false;
+
+class DexCompiler {
+ public:
+ DexCompiler(art::CompilerDriver& compiler,
+ const DexCompilationUnit& unit)
+ : driver_(compiler),
+ unit_(unit) {};
+
+ ~DexCompiler() {};
+
+ void Compile();
+
+ private:
+ const DexFile& GetDexFile() const {
+ return *unit_.GetDexFile();
+ }
+
+ // TODO: since the whole compilation pipeline uses a "const DexFile", we need
+ // to "unconst" here. The DEX-to-DEX compiler should work on a non-const DexFile.
+ DexFile& GetModifiableDexFile() {
+ return *const_cast<DexFile*>(unit_.GetDexFile());
+ }
+
+ void CompileInstanceFieldAccess(Instruction* inst, uint32_t dex_pc,
+ Instruction::Code new_opcode, bool is_put);
+ void CompileInvokeVirtual(Instruction* inst, uint32_t dex_pc,
+ Instruction::Code new_opcode, bool is_range);
+
+ CompilerDriver& driver_;
+ const DexCompilationUnit& unit_;
+
+ DISALLOW_COPY_AND_ASSIGN(DexCompiler);
+};
+
+// Ensures write access to a part of DEX file.
+//
+// If a DEX file is read-only, it modifies its protection (mprotect) so it allows
+// write access to the part of DEX file defined by an address and a length.
+// In this case, it also takes the DexFile::modification_lock to prevent from
+// concurrent protection modification from a parallel DEX-to-DEX compilation on
+// the same DEX file.
+// When the instance is destroyed, it recovers original protection and releases
+// the lock.
+// TODO: as this scoped class is similar to a MutexLock we should use annotalysis
+// to capture the locking behavior.
+class ScopedDexWriteAccess {
+ public:
+ ScopedDexWriteAccess(DexFile& dex_file, Instruction* inst,
+ size_t length)
+ : dex_file_(dex_file),
+ address_(reinterpret_cast<uint8_t*>(inst)),
+ length_(length),
+ is_read_only_(dex_file_.IsReadOnly()) {
+ if (is_read_only_) {
+ // We need to enable DEX write access. To avoid concurrent DEX write access
+ // modification, we take the DexFile::modification_lock before.
+ dex_file_.GetModificationLock().ExclusiveLock(Thread::Current());
+ bool success = dex_file_.EnableWrite(address_, length_);
+ DCHECK(success) << "Failed to enable DEX write access";
+ }
+ }
+
+ ~ScopedDexWriteAccess() {
+ DCHECK_EQ(is_read_only_, dex_file_.IsReadOnly());
+ if (is_read_only_) {
+ bool success = dex_file_.DisableWrite(address_, length_);
+ DCHECK(success) << "Failed to disable DEX write access";
+ // Now we recovered original read-only protection, we can release the
+ // DexFile::modification_lock.
+ dex_file_.GetModificationLock().ExclusiveUnlock(Thread::Current());
+ }
+ }
+
+ private:
+ DexFile& dex_file_;
+ // TODO: make address_ const.
+ uint8_t* address_;
+ const size_t length_;
+ const bool is_read_only_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedDexWriteAccess);
+};
+
+void DexCompiler::Compile() {
+ const DexFile::CodeItem* code_item = unit_.GetCodeItem();
+ const uint16_t* insns = code_item->insns_;
+ const uint32_t insns_size = code_item->insns_size_in_code_units_;
+ Instruction* inst = const_cast<Instruction*>(Instruction::At(insns));
+
+ for (uint32_t dex_pc = 0; dex_pc < insns_size;
+ inst = const_cast<Instruction*>(inst->Next()), dex_pc = inst->GetDexPc(insns)) {
+ switch (inst->Opcode()) {
+ case Instruction::IGET:
+ CompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_QUICK, false);
+ break;
+ case Instruction::IGET_WIDE:
+ CompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_WIDE_QUICK, false);
+ break;
+
+ case Instruction::IGET_OBJECT:
+ CompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_OBJECT_QUICK, false);
+ break;
+
+ case Instruction::IPUT:
+ case Instruction::IPUT_BOOLEAN:
+ case Instruction::IPUT_BYTE:
+ case Instruction::IPUT_CHAR:
+ case Instruction::IPUT_SHORT:
+ // These opcodes have the same implementation in interpreter so group
+ // them under IPUT_QUICK.
+ CompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT_QUICK, true);
+ break;
+
+ case Instruction::IPUT_WIDE:
+ CompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT_WIDE_QUICK, true);
+ break;
+
+ case Instruction::IPUT_OBJECT:
+ CompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT_OBJECT_QUICK, true);
+ break;
+
+ case Instruction::INVOKE_VIRTUAL:
+ CompileInvokeVirtual(inst, dex_pc, Instruction::INVOKE_VIRTUAL_QUICK, false);
+ break;
+
+ case Instruction::INVOKE_VIRTUAL_RANGE:
+ CompileInvokeVirtual(inst, dex_pc, Instruction::INVOKE_VIRTUAL_RANGE_QUICK, true);
+ break;
+
+ default:
+ // No optimization.
+ break;
+ }
+ }
+}
+
+void DexCompiler::CompileInstanceFieldAccess(Instruction* inst,
+ uint32_t dex_pc,
+ Instruction::Code new_opcode,
+ bool is_put) {
+ if (!kEnableQuickening) {
+ return;
+ }
+ uint32_t field_idx = inst->VRegC_22c();
+ int field_offset;
+ bool is_volatile;
+ bool fast_path = driver_.ComputeInstanceFieldInfo(field_idx, &unit_, field_offset,
+ is_volatile, is_put);
+ if (fast_path && !is_volatile && IsUint(16, field_offset)) {
+ // TODO: use VLOG ?
+ if (kEnableLogging) {
+ LOG(INFO) << "Quickening " << Instruction::Name(inst->Opcode())
+ << " to " << Instruction::Name(new_opcode)
+ << " by replacing field index " << field_idx
+ << " by field offset " << field_offset
+ << " at dex pc " << StringPrintf("0x%x", dex_pc) << " in method "
+ << PrettyMethod(unit_.GetDexMethodIndex(), GetDexFile(), true);
+ }
+ // We are modifying 4 consecutive bytes.
+ ScopedDexWriteAccess sdwa(GetModifiableDexFile(), inst, 4u);
+ inst->SetOpcode(new_opcode);
+ // Replace field index by field offset.
+ inst->SetVRegC_22c(static_cast<uint16_t>(field_offset));
+ }
+}
+
+void DexCompiler::CompileInvokeVirtual(Instruction* inst,
+ uint32_t dex_pc,
+ Instruction::Code new_opcode,
+ bool is_range) {
+ if (!kEnableQuickening) {
+ return;
+ }
+ uint32_t method_idx = is_range ? inst->VRegB_3rc() : inst->VRegB_35c();
+ CompilerDriver::MethodReference target_method(&GetDexFile(), method_idx);
+ InvokeType invoke_type = kVirtual;
+ InvokeType original_invoke_type = invoke_type;
+ int vtable_idx;
+ uintptr_t direct_code;
+ uintptr_t direct_method;
+ bool fast_path = driver_.ComputeInvokeInfo(&unit_, dex_pc, invoke_type,
+ target_method, vtable_idx,
+ direct_code, direct_method,
+ false);
+ // TODO: support devirtualization.
+ if (fast_path && original_invoke_type == invoke_type) {
+ if (vtable_idx >= 0 && IsUint(16, vtable_idx)) {
+ // TODO: use VLOG ?
+ if (kEnableLogging) {
+ LOG(INFO) << "Quickening " << Instruction::Name(inst->Opcode())
+ << "(" << PrettyMethod(method_idx, GetDexFile(), true) << ")"
+ << " to " << Instruction::Name(new_opcode)
+ << " by replacing method index " << method_idx
+ << " by vtable index " << vtable_idx
+ << " at dex pc " << StringPrintf("0x%x", dex_pc) << " in method "
+ << PrettyMethod(unit_.GetDexMethodIndex(), GetDexFile(), true);
+ }
+ // We are modifying 4 consecutive bytes.
+ ScopedDexWriteAccess sdwa(GetModifiableDexFile(), inst, 4u);
+ inst->SetOpcode(new_opcode);
+ // Replace method index by vtable index.
+ if (is_range) {
+ inst->SetVRegB_3rc(static_cast<uint16_t>(vtable_idx));
+ } else {
+ inst->SetVRegB_35c(static_cast<uint16_t>(vtable_idx));
+ }
+ }
+ }
+}
+
+} // namespace optimizer
+} // namespace art
+
+extern "C" art::CompiledMethod*
+ ArtCompileDEX(art::CompilerDriver& compiler, const art::DexFile::CodeItem* code_item,
+ uint32_t access_flags, art::InvokeType invoke_type,
+ uint32_t class_def_idx, uint32_t method_idx, jobject class_loader,
+ const art::DexFile& dex_file) {
+ art::DexCompilationUnit unit(NULL, class_loader, art::Runtime::Current()->GetClassLinker(),
+ dex_file, code_item, class_def_idx, method_idx, access_flags);
+ art::optimizer::DexCompiler dex_compiler(compiler, unit);
+ dex_compiler.Compile();
+ return NULL;
+}
diff --git a/src/compiler/dex/frontend.cc b/src/compiler/dex/frontend.cc
index ca751ab849..c528d8680c 100644
--- a/src/compiler/dex/frontend.cc
+++ b/src/compiler/dex/frontend.cc
@@ -18,7 +18,7 @@
#include "compiler/driver/compiler_driver.h"
#include "compiler_internals.h"
-#include "dataflow_iterator.h"
+#include "dataflow_iterator-inl.h"
#if defined(ART_USE_PORTABLE_COMPILER)
#include "compiler/llvm/llvm_compilation_unit.h"
#include "compiler/dex/portable/mir_to_gbc.h"
@@ -29,6 +29,8 @@
#include "backend.h"
#include "base/logging.h"
+
+
namespace {
#if !defined(ART_USE_PORTABLE_COMPILER)
pthread_once_t llvm_multi_init = PTHREAD_ONCE_INIT;
@@ -104,6 +106,7 @@ static uint32_t kCompilerDebugFlags = 0 | // Enable debug/testing modes
//(1 << kDebugShowSummaryMemoryUsage) |
0;
+
static CompiledMethod* CompileMethod(CompilerDriver& compiler,
const CompilerBackend compiler_backend,
const DexFile::CodeItem* code_item,
@@ -277,6 +280,8 @@ CompiledMethod* CompileOneMethod(CompilerDriver& compiler,
);
}
+
+
} // namespace art
extern "C" art::CompiledMethod*
diff --git a/src/compiler/dex/frontend.h b/src/compiler/dex/frontend.h
index dc57a23485..69d7f7728c 100644
--- a/src/compiler/dex/frontend.h
+++ b/src/compiler/dex/frontend.h
@@ -20,6 +20,11 @@
#include "dex_file.h"
#include "dex_instruction.h"
+
+
+
+
+
namespace llvm {
class Module;
class LLVMContext;
@@ -116,4 +121,6 @@ extern "C" art::CompiledMethod* ArtCompileMethod(art::CompilerDriver& driver,
jobject class_loader,
const art::DexFile& dex_file);
+
+
#endif // ART_SRC_COMPILER_DEX_COMPILER_H_
diff --git a/src/compiler/dex/mir_dataflow.cc b/src/compiler/dex/mir_dataflow.cc
index 9f61d73d6b..3b2c1a6c5e 100644
--- a/src/compiler/dex/mir_dataflow.cc
+++ b/src/compiler/dex/mir_dataflow.cc
@@ -16,7 +16,7 @@
#include "compiler_internals.h"
#include "local_value_numbering.h"
-#include "dataflow_iterator.h"
+#include "dataflow_iterator-inl.h"
namespace art {
@@ -70,7 +70,7 @@ const int MIRGraph::oat_data_flow_attributes_[kMirOpLast] = {
DF_DA | DF_REF_A,
// 0D MOVE_EXCEPTION vAA
- DF_DA | DF_REF_A,
+ DF_DA | DF_REF_A | DF_NON_NULL_DST,
// 0E RETURN_VOID
DF_NOP,
@@ -109,13 +109,13 @@ const int MIRGraph::oat_data_flow_attributes_[kMirOpLast] = {
DF_DA | DF_A_WIDE | DF_SETS_CONST,
// 1A CONST_STRING vAA, string@BBBB
- DF_DA | DF_REF_A,
+ DF_DA | DF_REF_A | DF_NON_NULL_DST,
// 1B CONST_STRING_JUMBO vAA, string@BBBBBBBB
- DF_DA | DF_REF_A,
+ DF_DA | DF_REF_A | DF_NON_NULL_DST,
// 1C CONST_CLASS vAA, type@BBBB
- DF_DA | DF_REF_A,
+ DF_DA | DF_REF_A | DF_NON_NULL_DST,
// 1D MONITOR_ENTER vAA
DF_UA | DF_NULL_CHK_0 | DF_REF_A,
@@ -933,11 +933,6 @@ int MIRGraph::AddNewSReg(int v_reg)
SetNumSSARegs(ssa_reg + 1);
ssa_base_vregs_->Insert(v_reg);
ssa_subscripts_->Insert(subscript);
- std::string ssa_name = GetSSAName(ssa_reg);
- char* name = static_cast<char*>(arena_->NewMem(ssa_name.length() + 1, false,
- ArenaAllocator::kAllocDFInfo));
- strncpy(name, ssa_name.c_str(), ssa_name.length() + 1);
- ssa_strings_->Insert(name);
DCHECK_EQ(ssa_base_vregs_->Size(), ssa_subscripts_->Size());
return ssa_reg;
}
@@ -1140,8 +1135,6 @@ void MIRGraph::CompilerInitializeSSAConversion()
kGrowableArraySSAtoDalvikMap);
ssa_subscripts_ = new (arena_) GrowableArray<int>(arena_, num_dalvik_reg + GetDefCount() + 128,
kGrowableArraySSAtoDalvikMap);
- ssa_strings_ = new (arena_) GrowableArray<char*>(arena_, num_dalvik_reg + GetDefCount() + 128,
- kGrowableArraySSAtoDalvikMap);
/*
* Initial number of SSA registers is equal to the number of Dalvik
* registers.
@@ -1156,11 +1149,6 @@ void MIRGraph::CompilerInitializeSSAConversion()
for (unsigned int i = 0; i < num_dalvik_reg; i++) {
ssa_base_vregs_->Insert(i);
ssa_subscripts_->Insert(0);
- std::string ssa_name = GetSSAName(i);
- char* name = static_cast<char*>(arena_->NewMem(ssa_name.length() + 1, true,
- ArenaAllocator::kAllocDFInfo));
- strncpy(name, ssa_name.c_str(), ssa_name.length() + 1);
- ssa_strings_->Insert(name);
}
/*
@@ -1237,17 +1225,17 @@ bool MIRGraph::InvokeUsesMethodStar(MIR* mir)
return false;
}
DexCompilationUnit m_unit(cu_);
- // TODO: add a flag so we don't counts the stats for this twice
- uint32_t dex_method_idx = mir->dalvikInsn.vB;
+ CompilerDriver::MethodReference target_method(cu_->dex_file, mir->dalvikInsn.vB);
int vtable_idx;
uintptr_t direct_code;
uintptr_t direct_method;
uint32_t current_offset = static_cast<uint32_t>(current_offset_);
bool fast_path =
- cu_->compiler_driver->ComputeInvokeInfo(dex_method_idx, current_offset,
- &m_unit, type,
- vtable_idx, direct_code,
- direct_method) &&
+ cu_->compiler_driver->ComputeInvokeInfo(&m_unit, current_offset,
+ type, target_method,
+ vtable_idx,
+ direct_code, direct_method,
+ false) &&
!(cu_->enable_debug & (1 << kDebugSlowInvokePath));
return (((type == kDirect) || (type == kStatic)) &&
fast_path && ((direct_code == 0) || (direct_method == 0)));
diff --git a/src/compiler/dex/mir_graph.cc b/src/compiler/dex/mir_graph.cc
index 6154eec6ca..11e100dc61 100644
--- a/src/compiler/dex/mir_graph.cc
+++ b/src/compiler/dex/mir_graph.cc
@@ -77,7 +77,6 @@ MIRGraph::MIRGraph(CompilationUnit* cu, ArenaAllocator* arena)
cu_(cu),
ssa_base_vregs_(NULL),
ssa_subscripts_(NULL),
- ssa_strings_(NULL),
vreg_to_ssa_map_(NULL),
ssa_last_defs_(NULL),
is_constant_v_(NULL),
@@ -1037,6 +1036,9 @@ void MIRGraph::ReplaceSpecialChars(std::string& str)
std::string MIRGraph::GetSSAName(int ssa_reg)
{
+ // TODO: This value is needed for LLVM and debugging. Currently, we compute this and then copy to
+ // the arena. We should be smarter and just place straight into the arena, or compute the
+ // value more lazily.
return StringPrintf("v%d_%d", SRegToVReg(ssa_reg), GetSSASubscript(ssa_reg));
}
diff --git a/src/compiler/dex/mir_graph.h b/src/compiler/dex/mir_graph.h
index 882a5088d7..2b1c21fd70 100644
--- a/src/compiler/dex/mir_graph.h
+++ b/src/compiler/dex/mir_graph.h
@@ -452,10 +452,6 @@ class MIRGraph {
return ssa_subscripts_->Get(ssa_reg);
}
- const char* GetSSAString(int ssa_reg) const {
- return ssa_strings_->Get(ssa_reg);
- }
-
RegLocation GetRawSrc(MIR* mir, int num)
{
DCHECK(num < mir->ssa_rep->num_uses);
@@ -628,7 +624,6 @@ class MIRGraph {
CompilationUnit* const cu_;
GrowableArray<int>* ssa_base_vregs_;
GrowableArray<int>* ssa_subscripts_;
- GrowableArray<char*>* ssa_strings_;
// Map original Dalvik virtual reg i to the current SSA name.
int* vreg_to_ssa_map_; // length == method->registers_size
int* ssa_last_defs_; // length == method->registers_size
diff --git a/src/compiler/dex/mir_optimization.cc b/src/compiler/dex/mir_optimization.cc
index 534550112a..6b8f3f0915 100644
--- a/src/compiler/dex/mir_optimization.cc
+++ b/src/compiler/dex/mir_optimization.cc
@@ -16,7 +16,7 @@
#include "compiler_internals.h"
#include "local_value_numbering.h"
-#include "dataflow_iterator.h"
+#include "dataflow_iterator-inl.h"
namespace art {
@@ -418,6 +418,13 @@ bool MIRGraph::BasicBlockOpt(BasicBlock* bb)
static_cast<bool*>(arena_->NewMem(sizeof(bool) * 1, false,
ArenaAllocator::kAllocDFInfo));
mir->ssa_rep->fp_def[0] = if_true->ssa_rep->fp_def[0];
+ // Match type of uses to def.
+ mir->ssa_rep->fp_use =
+ static_cast<bool*>(arena_->NewMem(sizeof(bool) * mir->ssa_rep->num_uses, false,
+ ArenaAllocator::kAllocDFInfo));
+ for (int i = 0; i < mir->ssa_rep->num_uses; i++) {
+ mir->ssa_rep->fp_use[i] = mir->ssa_rep->fp_def[0];
+ }
/*
* There is usually a Phi node in the join block for our two cases. If the
* Phi node only contains our two cases as input, we will use the result
@@ -634,8 +641,29 @@ bool MIRGraph::EliminateNullChecks(struct BasicBlock* bb)
int this_reg = cu_->num_dalvik_registers - cu_->num_ins;
temp_ssa_register_v_->SetBit(this_reg);
}
+ } else if (bb->predecessors->Size() == 1) {
+ BasicBlock* pred_bb = bb->predecessors->Get(0);
+ temp_ssa_register_v_->Copy(pred_bb->data_flow_info->ending_null_check_v);
+ if (pred_bb->block_type == kDalvikByteCode) {
+ // Check to see if predecessor had an explicit null-check.
+ MIR* last_insn = pred_bb->last_mir_insn;
+ Instruction::Code last_opcode = last_insn->dalvikInsn.opcode;
+ if (last_opcode == Instruction::IF_EQZ) {
+ if (pred_bb->fall_through == bb) {
+ // The fall-through of a block following a IF_EQZ, set the vA of the IF_EQZ to show that
+ // it can't be null.
+ temp_ssa_register_v_->SetBit(last_insn->ssa_rep->uses[0]);
+ }
+ } else if (last_opcode == Instruction::IF_NEZ) {
+ if (pred_bb->taken == bb) {
+ // The taken block following a IF_NEZ, set the vA of the IF_NEZ to show that it can't be
+ // null.
+ temp_ssa_register_v_->SetBit(last_insn->ssa_rep->uses[0]);
+ }
+ }
+ }
} else {
- // Starting state is intesection of all incoming arcs
+ // Starting state is intersection of all incoming arcs
GrowableArray<BasicBlock*>::Iterator iter(bb->predecessors);
BasicBlock* pred_bb = iter.Next();
DCHECK(pred_bb != NULL);
diff --git a/src/compiler/dex/portable/mir_to_gbc.cc b/src/compiler/dex/portable/mir_to_gbc.cc
index 6fccb47d9f..1f9c92a3d2 100644
--- a/src/compiler/dex/portable/mir_to_gbc.cc
+++ b/src/compiler/dex/portable/mir_to_gbc.cc
@@ -28,7 +28,7 @@
#include <llvm/Support/ToolOutputFile.h>
#include "compiler/dex/compiler_internals.h"
-#include "compiler/dex/dataflow_iterator.h"
+#include "compiler/dex/dataflow_iterator-inl.h"
#include "compiler/dex/frontend.h"
#include "mir_to_gbc.h"
@@ -1964,7 +1964,7 @@ void MirConverter::MethodMIR2Bitcode()
::llvm::Constant* imm_value = mir_graph_->reg_location_[i].wide ?
irb_->getJLong(0) : irb_->getJInt(0);
val = EmitConst(imm_value, mir_graph_->reg_location_[i]);
- val->setName(mir_graph_->GetSSAString(i));
+ val->setName(mir_graph_->GetSSAName(i));
llvm_values_.Insert(val);
} else {
// Recover previously-created argument values
diff --git a/src/compiler/dex/quick/arm/assemble_arm.cc b/src/compiler/dex/quick/arm/assemble_arm.cc
index 23a87dcec1..36038f7741 100644
--- a/src/compiler/dex/quick/arm/assemble_arm.cc
+++ b/src/compiler/dex/quick/arm/assemble_arm.cc
@@ -16,6 +16,7 @@
#include "arm_lir.h"
#include "codegen_arm.h"
+#include "compiler/dex/quick/mir_to_lir-inl.h"
namespace art {
diff --git a/src/compiler/dex/quick/arm/call_arm.cc b/src/compiler/dex/quick/arm/call_arm.cc
index 32d4ed680f..879065f570 100644
--- a/src/compiler/dex/quick/arm/call_arm.cc
+++ b/src/compiler/dex/quick/arm/call_arm.cc
@@ -18,6 +18,7 @@
#include "arm_lir.h"
#include "codegen_arm.h"
+#include "compiler/dex/quick/mir_to_lir-inl.h"
#include "oat/runtime/oat_support_entrypoints.h"
namespace art {
@@ -561,7 +562,7 @@ void ArmMir2Lir::MarkGCCard(int val_reg, int tgt_addr_reg)
int reg_card_no = AllocTemp();
LIR* branch_over = OpCmpImmBranch(kCondEq, val_reg, 0, NULL);
LoadWordDisp(rARM_SELF, Thread::CardTableOffset().Int32Value(), reg_card_base);
- OpRegRegImm(kOpLsr, reg_card_no, tgt_addr_reg, CardTable::kCardShift);
+ OpRegRegImm(kOpLsr, reg_card_no, tgt_addr_reg, gc::accounting::CardTable::kCardShift);
StoreBaseIndexed(reg_card_base, reg_card_no, reg_card_base, 0,
kUnsignedByte);
LIR* target = NewLIR0(kPseudoTargetLabel);
diff --git a/src/compiler/dex/quick/arm/codegen_arm.h b/src/compiler/dex/quick/arm/codegen_arm.h
index 9e409e6772..60111d1d06 100644
--- a/src/compiler/dex/quick/arm/codegen_arm.h
+++ b/src/compiler/dex/quick/arm/codegen_arm.h
@@ -23,143 +23,142 @@ namespace art {
class ArmMir2Lir : public Mir2Lir {
public:
-
ArmMir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena);
// Required for target - codegen helpers.
- virtual bool SmallLiteralDivide(Instruction::Code dalvik_opcode, RegLocation rl_src,
+ bool SmallLiteralDivide(Instruction::Code dalvik_opcode, RegLocation rl_src,
RegLocation rl_dest, int lit);
- virtual int LoadHelper(int offset);
- virtual LIR* LoadBaseDisp(int rBase, int displacement, int r_dest, OpSize size, int s_reg);
- virtual LIR* LoadBaseDispWide(int rBase, int displacement, int r_dest_lo, int r_dest_hi,
- int s_reg);
- virtual LIR* LoadBaseIndexed(int rBase, int r_index, int r_dest, int scale, OpSize size);
- virtual LIR* LoadBaseIndexedDisp(int rBase, int r_index, int scale, int displacement,
- int r_dest, int r_dest_hi, OpSize size, int s_reg);
- virtual LIR* LoadConstantNoClobber(int r_dest, int value);
- virtual LIR* LoadConstantWide(int r_dest_lo, int r_dest_hi, int64_t value);
- virtual LIR* StoreBaseDisp(int rBase, int displacement, int r_src, OpSize size);
- virtual LIR* StoreBaseDispWide(int rBase, int displacement, int r_src_lo, int r_src_hi);
- virtual LIR* StoreBaseIndexed(int rBase, int r_index, int r_src, int scale, OpSize size);
- virtual LIR* StoreBaseIndexedDisp(int rBase, int r_index, int scale, int displacement,
- int r_src, int r_src_hi, OpSize size, int s_reg);
- virtual void MarkGCCard(int val_reg, int tgt_addr_reg);
+ int LoadHelper(int offset);
+ LIR* LoadBaseDisp(int rBase, int displacement, int r_dest, OpSize size, int s_reg);
+ LIR* LoadBaseDispWide(int rBase, int displacement, int r_dest_lo, int r_dest_hi,
+ int s_reg);
+ LIR* LoadBaseIndexed(int rBase, int r_index, int r_dest, int scale, OpSize size);
+ LIR* LoadBaseIndexedDisp(int rBase, int r_index, int scale, int displacement,
+ int r_dest, int r_dest_hi, OpSize size, int s_reg);
+ LIR* LoadConstantNoClobber(int r_dest, int value);
+ LIR* LoadConstantWide(int r_dest_lo, int r_dest_hi, int64_t value);
+ LIR* StoreBaseDisp(int rBase, int displacement, int r_src, OpSize size);
+ LIR* StoreBaseDispWide(int rBase, int displacement, int r_src_lo, int r_src_hi);
+ LIR* StoreBaseIndexed(int rBase, int r_index, int r_src, int scale, OpSize size);
+ LIR* StoreBaseIndexedDisp(int rBase, int r_index, int scale, int displacement,
+ int r_src, int r_src_hi, OpSize size, int s_reg);
+ void MarkGCCard(int val_reg, int tgt_addr_reg);
// Required for target - register utilities.
- virtual bool IsFpReg(int reg);
- virtual bool SameRegType(int reg1, int reg2);
- virtual int AllocTypedTemp(bool fp_hint, int reg_class);
- virtual int AllocTypedTempPair(bool fp_hint, int reg_class);
- virtual int S2d(int low_reg, int high_reg);
- virtual int TargetReg(SpecialTargetRegister reg);
- virtual RegisterInfo* GetRegInfo(int reg);
- virtual RegLocation GetReturnAlt();
- virtual RegLocation GetReturnWideAlt();
- virtual RegLocation LocCReturn();
- virtual RegLocation LocCReturnDouble();
- virtual RegLocation LocCReturnFloat();
- virtual RegLocation LocCReturnWide();
- virtual uint32_t FpRegMask();
- virtual uint64_t GetRegMaskCommon(int reg);
- virtual void AdjustSpillMask();
- virtual void ClobberCalleeSave();
- virtual void FlushReg(int reg);
- virtual void FlushRegWide(int reg1, int reg2);
- virtual void FreeCallTemps();
- virtual void FreeRegLocTemps(RegLocation rl_keep, RegLocation rl_free);
- virtual void LockCallTemps();
- virtual void MarkPreservedSingle(int v_reg, int reg);
- virtual void CompilerInitializeRegAlloc();
+ bool IsFpReg(int reg);
+ bool SameRegType(int reg1, int reg2);
+ int AllocTypedTemp(bool fp_hint, int reg_class);
+ int AllocTypedTempPair(bool fp_hint, int reg_class);
+ int S2d(int low_reg, int high_reg);
+ int TargetReg(SpecialTargetRegister reg);
+ RegisterInfo* GetRegInfo(int reg);
+ RegLocation GetReturnAlt();
+ RegLocation GetReturnWideAlt();
+ RegLocation LocCReturn();
+ RegLocation LocCReturnDouble();
+ RegLocation LocCReturnFloat();
+ RegLocation LocCReturnWide();
+ uint32_t FpRegMask();
+ uint64_t GetRegMaskCommon(int reg);
+ void AdjustSpillMask();
+ void ClobberCalleeSave();
+ void FlushReg(int reg);
+ void FlushRegWide(int reg1, int reg2);
+ void FreeCallTemps();
+ void FreeRegLocTemps(RegLocation rl_keep, RegLocation rl_free);
+ void LockCallTemps();
+ void MarkPreservedSingle(int v_reg, int reg);
+ void CompilerInitializeRegAlloc();
// Required for target - miscellaneous.
- virtual AssemblerStatus AssembleInstructions(uintptr_t start_addr);
- virtual void DumpResourceMask(LIR* lir, uint64_t mask, const char* prefix);
- virtual void SetupTargetResourceMasks(LIR* lir);
- virtual const char* GetTargetInstFmt(int opcode);
- virtual const char* GetTargetInstName(int opcode);
- virtual std::string BuildInsnString(const char* fmt, LIR* lir, unsigned char* base_addr);
- virtual uint64_t GetPCUseDefEncoding();
- virtual uint64_t GetTargetInstFlags(int opcode);
- virtual int GetInsnSize(LIR* lir);
- virtual bool IsUnconditionalBranch(LIR* lir);
+ AssemblerStatus AssembleInstructions(uintptr_t start_addr);
+ void DumpResourceMask(LIR* lir, uint64_t mask, const char* prefix);
+ void SetupTargetResourceMasks(LIR* lir);
+ const char* GetTargetInstFmt(int opcode);
+ const char* GetTargetInstName(int opcode);
+ std::string BuildInsnString(const char* fmt, LIR* lir, unsigned char* base_addr);
+ uint64_t GetPCUseDefEncoding();
+ uint64_t GetTargetInstFlags(int opcode);
+ int GetInsnSize(LIR* lir);
+ bool IsUnconditionalBranch(LIR* lir);
// Required for target - Dalvik-level generators.
- virtual void GenArithImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
- RegLocation rl_src1, RegLocation rl_src2);
- virtual void GenArrayObjPut(int opt_flags, RegLocation rl_array, RegLocation rl_index,
- RegLocation rl_src, int scale);
- virtual void GenArrayGet(int opt_flags, OpSize size, RegLocation rl_array,
- RegLocation rl_index, RegLocation rl_dest, int scale);
- virtual void GenArrayPut(int opt_flags, OpSize size, RegLocation rl_array,
- RegLocation rl_index, RegLocation rl_src, int scale);
- virtual void GenShiftImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
- RegLocation rl_src1, RegLocation rl_shift);
- virtual void GenMulLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
- virtual void GenAddLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
- virtual void GenAndLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
- virtual void GenArithOpDouble(Instruction::Code opcode, RegLocation rl_dest,
- RegLocation rl_src1, RegLocation rl_src2);
- virtual void GenArithOpFloat(Instruction::Code opcode, RegLocation rl_dest,
- RegLocation rl_src1, RegLocation rl_src2);
- virtual void GenCmpFP(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
- RegLocation rl_src2);
- virtual void GenConversion(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src);
- virtual bool GenInlinedCas32(CallInfo* info, bool need_write_barrier);
- virtual bool GenInlinedMinMaxInt(CallInfo* info, bool is_min);
- virtual bool GenInlinedSqrt(CallInfo* info);
- virtual void GenNegLong(RegLocation rl_dest, RegLocation rl_src);
- virtual void GenOrLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
- virtual void GenSubLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
- virtual void GenXorLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
- virtual LIR* GenRegMemCheck(ConditionCode c_code, int reg1, int base, int offset,
+ void GenArithImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
+ RegLocation rl_src1, RegLocation rl_src2);
+ void GenArrayObjPut(int opt_flags, RegLocation rl_array, RegLocation rl_index,
+ RegLocation rl_src, int scale);
+ void GenArrayGet(int opt_flags, OpSize size, RegLocation rl_array,
+ RegLocation rl_index, RegLocation rl_dest, int scale);
+ void GenArrayPut(int opt_flags, OpSize size, RegLocation rl_array,
+ RegLocation rl_index, RegLocation rl_src, int scale);
+ void GenShiftImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
+ RegLocation rl_src1, RegLocation rl_shift);
+ void GenMulLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+ void GenAddLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+ void GenAndLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+ void GenArithOpDouble(Instruction::Code opcode, RegLocation rl_dest,
+ RegLocation rl_src1, RegLocation rl_src2);
+ void GenArithOpFloat(Instruction::Code opcode, RegLocation rl_dest,
+ RegLocation rl_src1, RegLocation rl_src2);
+ void GenCmpFP(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
+ RegLocation rl_src2);
+ void GenConversion(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src);
+ bool GenInlinedCas32(CallInfo* info, bool need_write_barrier);
+ bool GenInlinedMinMaxInt(CallInfo* info, bool is_min);
+ bool GenInlinedSqrt(CallInfo* info);
+ void GenNegLong(RegLocation rl_dest, RegLocation rl_src);
+ void GenOrLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+ void GenSubLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+ void GenXorLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+ LIR* GenRegMemCheck(ConditionCode c_code, int reg1, int base, int offset,
ThrowKind kind);
- virtual RegLocation GenDivRem(RegLocation rl_dest, int reg_lo, int reg_hi, bool is_div);
- virtual RegLocation GenDivRemLit(RegLocation rl_dest, int reg_lo, int lit, bool is_div);
- virtual void GenCmpLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
- virtual void GenDivZeroCheck(int reg_lo, int reg_hi);
- virtual void GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method);
- virtual void GenExitSequence();
- virtual void GenFillArrayData(uint32_t table_offset, RegLocation rl_src);
- virtual void GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias, bool is_double);
- virtual void GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir);
- virtual void GenSelect(BasicBlock* bb, MIR* mir);
- virtual void GenMemBarrier(MemBarrierKind barrier_kind);
- virtual void GenMonitorEnter(int opt_flags, RegLocation rl_src);
- virtual void GenMonitorExit(int opt_flags, RegLocation rl_src);
- virtual void GenMoveException(RegLocation rl_dest);
- virtual void GenMultiplyByTwoBitMultiplier(RegLocation rl_src, RegLocation rl_result, int lit,
+ RegLocation GenDivRem(RegLocation rl_dest, int reg_lo, int reg_hi, bool is_div);
+ RegLocation GenDivRemLit(RegLocation rl_dest, int reg_lo, int lit, bool is_div);
+ void GenCmpLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+ void GenDivZeroCheck(int reg_lo, int reg_hi);
+ void GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method);
+ void GenExitSequence();
+ void GenFillArrayData(uint32_t table_offset, RegLocation rl_src);
+ void GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias, bool is_double);
+ void GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir);
+ void GenSelect(BasicBlock* bb, MIR* mir);
+ void GenMemBarrier(MemBarrierKind barrier_kind);
+ void GenMonitorEnter(int opt_flags, RegLocation rl_src);
+ void GenMonitorExit(int opt_flags, RegLocation rl_src);
+ void GenMoveException(RegLocation rl_dest);
+ void GenMultiplyByTwoBitMultiplier(RegLocation rl_src, RegLocation rl_result, int lit,
int first_bit, int second_bit);
- virtual void GenNegDouble(RegLocation rl_dest, RegLocation rl_src);
- virtual void GenNegFloat(RegLocation rl_dest, RegLocation rl_src);
- virtual void GenPackedSwitch(MIR* mir, uint32_t table_offset, RegLocation rl_src);
- virtual void GenSparseSwitch(MIR* mir, uint32_t table_offset, RegLocation rl_src);
- virtual void GenSpecialCase(BasicBlock* bb, MIR* mir, SpecialCaseHandler special_case);
+ void GenNegDouble(RegLocation rl_dest, RegLocation rl_src);
+ void GenNegFloat(RegLocation rl_dest, RegLocation rl_src);
+ void GenPackedSwitch(MIR* mir, uint32_t table_offset, RegLocation rl_src);
+ void GenSparseSwitch(MIR* mir, uint32_t table_offset, RegLocation rl_src);
+ void GenSpecialCase(BasicBlock* bb, MIR* mir, SpecialCaseHandler special_case);
// Required for target - single operation generators.
- virtual LIR* OpUnconditionalBranch(LIR* target);
- virtual LIR* OpCmpBranch(ConditionCode cond, int src1, int src2, LIR* target);
- virtual LIR* OpCmpImmBranch(ConditionCode cond, int reg, int check_value, LIR* target);
- virtual LIR* OpCondBranch(ConditionCode cc, LIR* target);
- virtual LIR* OpDecAndBranch(ConditionCode c_code, int reg, LIR* target);
- virtual LIR* OpFpRegCopy(int r_dest, int r_src);
- virtual LIR* OpIT(ConditionCode cond, const char* guide);
- virtual LIR* OpMem(OpKind op, int rBase, int disp);
- virtual LIR* OpPcRelLoad(int reg, LIR* target);
- virtual LIR* OpReg(OpKind op, int r_dest_src);
- virtual LIR* OpRegCopy(int r_dest, int r_src);
- virtual LIR* OpRegCopyNoInsert(int r_dest, int r_src);
- virtual LIR* OpRegImm(OpKind op, int r_dest_src1, int value);
- virtual LIR* OpRegMem(OpKind op, int r_dest, int rBase, int offset);
- virtual LIR* OpRegReg(OpKind op, int r_dest_src1, int r_src2);
- virtual LIR* OpRegRegImm(OpKind op, int r_dest, int r_src1, int value);
- virtual LIR* OpRegRegReg(OpKind op, int r_dest, int r_src1, int r_src2);
- virtual LIR* OpTestSuspend(LIR* target);
- virtual LIR* OpThreadMem(OpKind op, int thread_offset);
- virtual LIR* OpVldm(int rBase, int count);
- virtual LIR* OpVstm(int rBase, int count);
- virtual void OpLea(int rBase, int reg1, int reg2, int scale, int offset);
- virtual void OpRegCopyWide(int dest_lo, int dest_hi, int src_lo, int src_hi);
- virtual void OpTlsCmp(int offset, int val);
+ LIR* OpUnconditionalBranch(LIR* target);
+ LIR* OpCmpBranch(ConditionCode cond, int src1, int src2, LIR* target);
+ LIR* OpCmpImmBranch(ConditionCode cond, int reg, int check_value, LIR* target);
+ LIR* OpCondBranch(ConditionCode cc, LIR* target);
+ LIR* OpDecAndBranch(ConditionCode c_code, int reg, LIR* target);
+ LIR* OpFpRegCopy(int r_dest, int r_src);
+ LIR* OpIT(ConditionCode cond, const char* guide);
+ LIR* OpMem(OpKind op, int rBase, int disp);
+ LIR* OpPcRelLoad(int reg, LIR* target);
+ LIR* OpReg(OpKind op, int r_dest_src);
+ LIR* OpRegCopy(int r_dest, int r_src);
+ LIR* OpRegCopyNoInsert(int r_dest, int r_src);
+ LIR* OpRegImm(OpKind op, int r_dest_src1, int value);
+ LIR* OpRegMem(OpKind op, int r_dest, int rBase, int offset);
+ LIR* OpRegReg(OpKind op, int r_dest_src1, int r_src2);
+ LIR* OpRegRegImm(OpKind op, int r_dest, int r_src1, int value);
+ LIR* OpRegRegReg(OpKind op, int r_dest, int r_src1, int r_src2);
+ LIR* OpTestSuspend(LIR* target);
+ LIR* OpThreadMem(OpKind op, int thread_offset);
+ LIR* OpVldm(int rBase, int count);
+ LIR* OpVstm(int rBase, int count);
+ void OpLea(int rBase, int reg1, int reg2, int scale, int offset);
+ void OpRegCopyWide(int dest_lo, int dest_hi, int src_lo, int src_hi);
+ void OpTlsCmp(int offset, int val);
RegLocation ArgLoc(RegLocation loc);
LIR* LoadBaseDispBody(int rBase, int displacement, int r_dest, int r_dest_hi, OpSize size,
diff --git a/src/compiler/dex/quick/arm/fp_arm.cc b/src/compiler/dex/quick/arm/fp_arm.cc
index 4bf8738949..cd71c0798b 100644
--- a/src/compiler/dex/quick/arm/fp_arm.cc
+++ b/src/compiler/dex/quick/arm/fp_arm.cc
@@ -16,6 +16,7 @@
#include "arm_lir.h"
#include "codegen_arm.h"
+#include "compiler/dex/quick/mir_to_lir-inl.h"
namespace art {
diff --git a/src/compiler/dex/quick/arm/int_arm.cc b/src/compiler/dex/quick/arm/int_arm.cc
index 586a3a49b5..110e9f4320 100644
--- a/src/compiler/dex/quick/arm/int_arm.cc
+++ b/src/compiler/dex/quick/arm/int_arm.cc
@@ -18,6 +18,7 @@
#include "arm_lir.h"
#include "codegen_arm.h"
+#include "compiler/dex/quick/mir_to_lir-inl.h"
#include "mirror/array.h"
#include "oat/runtime/oat_support_entrypoints.h"
diff --git a/src/compiler/dex/quick/arm/target_arm.cc b/src/compiler/dex/quick/arm/target_arm.cc
index 0a05a3a431..ee127a8e17 100644
--- a/src/compiler/dex/quick/arm/target_arm.cc
+++ b/src/compiler/dex/quick/arm/target_arm.cc
@@ -19,6 +19,7 @@
#include "arm_lir.h"
#include "codegen_arm.h"
#include "compiler/dex/compiler_internals.h"
+#include "compiler/dex/quick/mir_to_lir-inl.h"
namespace art {
diff --git a/src/compiler/dex/quick/arm/utility_arm.cc b/src/compiler/dex/quick/arm/utility_arm.cc
index c689f72436..ef0cc72a5c 100644
--- a/src/compiler/dex/quick/arm/utility_arm.cc
+++ b/src/compiler/dex/quick/arm/utility_arm.cc
@@ -16,7 +16,7 @@
#include "arm_lir.h"
#include "codegen_arm.h"
-#include "compiler/dex/quick/mir_to_lir.h"
+#include "compiler/dex/quick/mir_to_lir-inl.h"
namespace art {
diff --git a/src/compiler/dex/quick/codegen_util.cc b/src/compiler/dex/quick/codegen_util.cc
index 517d1b5c03..ac2828c276 100644
--- a/src/compiler/dex/quick/codegen_util.cc
+++ b/src/compiler/dex/quick/codegen_util.cc
@@ -17,6 +17,7 @@
#include "compiler/dex/compiler_internals.h"
#include "dex_file-inl.h"
#include "gc_map.h"
+#include "mir_to_lir-inl.h"
#include "verifier/dex_gc_map.h"
#include "verifier/method_verifier.h"
@@ -112,81 +113,6 @@ void Mir2Lir::AnnotateDalvikRegAccess(LIR* lir, int reg_id, bool is_load,
}
/*
- * Mark the corresponding bit(s).
- */
-void Mir2Lir::SetupRegMask(uint64_t* mask, int reg)
-{
- *mask |= GetRegMaskCommon(reg);
-}
-
-/*
- * Set up the proper fields in the resource mask
- */
-void Mir2Lir::SetupResourceMasks(LIR* lir)
-{
- int opcode = lir->opcode;
-
- if (opcode <= 0) {
- lir->use_mask = lir->def_mask = 0;
- return;
- }
-
- uint64_t flags = GetTargetInstFlags(opcode);
-
- if (flags & NEEDS_FIXUP) {
- lir->flags.pcRelFixup = true;
- }
-
- /* Get the starting size of the instruction's template */
- lir->flags.size = GetInsnSize(lir);
-
- /* Set up the mask for resources that are updated */
- if (flags & (IS_LOAD | IS_STORE)) {
- /* Default to heap - will catch specialized classes later */
- SetMemRefType(lir, flags & IS_LOAD, kHeapRef);
- }
-
- /*
- * Conservatively assume the branch here will call out a function that in
- * turn will trash everything.
- */
- if (flags & IS_BRANCH) {
- lir->def_mask = lir->use_mask = ENCODE_ALL;
- return;
- }
-
- if (flags & REG_DEF0) {
- SetupRegMask(&lir->def_mask, lir->operands[0]);
- }
-
- if (flags & REG_DEF1) {
- SetupRegMask(&lir->def_mask, lir->operands[1]);
- }
-
-
- if (flags & SETS_CCODES) {
- lir->def_mask |= ENCODE_CCODE;
- }
-
- if (flags & (REG_USE0 | REG_USE1 | REG_USE2 | REG_USE3)) {
- int i;
-
- for (i = 0; i < 4; i++) {
- if (flags & (1 << (kRegUse0 + i))) {
- SetupRegMask(&lir->use_mask, lir->operands[i]);
- }
- }
- }
-
- if (flags & USES_CCODES) {
- lir->use_mask |= ENCODE_CCODE;
- }
-
- // Handle target-specific actions
- SetupTargetResourceMasks(lir);
-}
-
-/*
* Debugging macros
*/
#define DUMP_RESOURCE_MASK(X)
@@ -361,99 +287,6 @@ void Mir2Lir::CodegenDump()
DumpMappingTable("Dex2PC_MappingTable", descriptor, name, signature, dex2pc_mapping_table_);
}
-
-LIR* Mir2Lir::RawLIR(int dalvik_offset, int opcode, int op0,
- int op1, int op2, int op3, int op4, LIR* target)
-{
- LIR* insn = static_cast<LIR*>(arena_->NewMem(sizeof(LIR), true, ArenaAllocator::kAllocLIR));
- insn->dalvik_offset = dalvik_offset;
- insn->opcode = opcode;
- insn->operands[0] = op0;
- insn->operands[1] = op1;
- insn->operands[2] = op2;
- insn->operands[3] = op3;
- insn->operands[4] = op4;
- insn->target = target;
- SetupResourceMasks(insn);
- if ((opcode == kPseudoTargetLabel) || (opcode == kPseudoSafepointPC) ||
- (opcode == kPseudoExportedPC)) {
- // Always make labels scheduling barriers
- insn->use_mask = insn->def_mask = ENCODE_ALL;
- }
- return insn;
-}
-
-/*
- * The following are building blocks to construct low-level IRs with 0 - 4
- * operands.
- */
-LIR* Mir2Lir::NewLIR0(int opcode)
-{
- DCHECK(is_pseudo_opcode(opcode) || (GetTargetInstFlags(opcode) & NO_OPERAND))
- << GetTargetInstName(opcode) << " " << opcode << " "
- << PrettyMethod(cu_->method_idx, *cu_->dex_file) << " "
- << current_dalvik_offset_;
- LIR* insn = RawLIR(current_dalvik_offset_, opcode);
- AppendLIR(insn);
- return insn;
-}
-
-LIR* Mir2Lir::NewLIR1(int opcode, int dest)
-{
- DCHECK(is_pseudo_opcode(opcode) || (GetTargetInstFlags(opcode) & IS_UNARY_OP))
- << GetTargetInstName(opcode) << " " << opcode << " "
- << PrettyMethod(cu_->method_idx, *cu_->dex_file) << " "
- << current_dalvik_offset_;
- LIR* insn = RawLIR(current_dalvik_offset_, opcode, dest);
- AppendLIR(insn);
- return insn;
-}
-
-LIR* Mir2Lir::NewLIR2(int opcode, int dest, int src1)
-{
- DCHECK(is_pseudo_opcode(opcode) || (GetTargetInstFlags(opcode) & IS_BINARY_OP))
- << GetTargetInstName(opcode) << " " << opcode << " "
- << PrettyMethod(cu_->method_idx, *cu_->dex_file) << " "
- << current_dalvik_offset_;
- LIR* insn = RawLIR(current_dalvik_offset_, opcode, dest, src1);
- AppendLIR(insn);
- return insn;
-}
-
-LIR* Mir2Lir::NewLIR3(int opcode, int dest, int src1, int src2)
-{
- DCHECK(is_pseudo_opcode(opcode) || (GetTargetInstFlags(opcode) & IS_TERTIARY_OP))
- << GetTargetInstName(opcode) << " " << opcode << " "
- << PrettyMethod(cu_->method_idx, *cu_->dex_file) << " "
- << current_dalvik_offset_;
- LIR* insn = RawLIR(current_dalvik_offset_, opcode, dest, src1, src2);
- AppendLIR(insn);
- return insn;
-}
-
-LIR* Mir2Lir::NewLIR4(int opcode, int dest, int src1, int src2, int info)
-{
- DCHECK(is_pseudo_opcode(opcode) || (GetTargetInstFlags(opcode) & IS_QUAD_OP))
- << GetTargetInstName(opcode) << " " << opcode << " "
- << PrettyMethod(cu_->method_idx, *cu_->dex_file) << " "
- << current_dalvik_offset_;
- LIR* insn = RawLIR(current_dalvik_offset_, opcode, dest, src1, src2, info);
- AppendLIR(insn);
- return insn;
-}
-
-LIR* Mir2Lir::NewLIR5(int opcode, int dest, int src1, int src2, int info1,
- int info2)
-{
- DCHECK(is_pseudo_opcode(opcode) || (GetTargetInstFlags(opcode) & IS_QUIN_OP))
- << GetTargetInstName(opcode) << " " << opcode << " "
- << PrettyMethod(cu_->method_idx, *cu_->dex_file) << " "
- << current_dalvik_offset_;
- LIR* insn = RawLIR(current_dalvik_offset_, opcode, dest, src1, src2, info1, info2);
- AppendLIR(insn);
- return insn;
-}
-
/*
* Search the existing constants in the literal pool for an exact or close match
* within specified delta (greater or equal to 0).
diff --git a/src/compiler/dex/quick/gen_common.cc b/src/compiler/dex/quick/gen_common.cc
index 15aa904f46..7aa71cfd10 100644
--- a/src/compiler/dex/quick/gen_common.cc
+++ b/src/compiler/dex/quick/gen_common.cc
@@ -16,8 +16,10 @@
#include "compiler/dex/compiler_ir.h"
#include "compiler/dex/compiler_internals.h"
+#include "compiler/dex/quick/mir_to_lir-inl.h"
#include "mirror/array.h"
#include "oat/runtime/oat_support_entrypoints.h"
+#include "verifier/method_verifier.h"
namespace art {
@@ -881,23 +883,81 @@ void Mir2Lir::GenThrow(RegLocation rl_src)
CallRuntimeHelperRegLocation(ENTRYPOINT_OFFSET(pDeliverException), rl_src, true);
}
-void Mir2Lir::GenInstanceof(uint32_t type_idx, RegLocation rl_dest,
- RegLocation rl_src)
-{
+// For final classes there are no sub-classes to check and so we can answer the instance-of
+// question with simple comparisons.
+void Mir2Lir::GenInstanceofFinal(bool use_declaring_class, uint32_t type_idx, RegLocation rl_dest,
+ RegLocation rl_src) {
+ RegLocation object = LoadValue(rl_src, kCoreReg);
+ RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
+ int result_reg = rl_result.low_reg;
+ if (result_reg == object.low_reg) {
+ result_reg = AllocTypedTemp(false, kCoreReg);
+ }
+ LoadConstant(result_reg, 0); // assume false
+ LIR* null_branchover = OpCmpImmBranch(kCondEq, object.low_reg, 0, NULL);
+
+ int check_class = AllocTypedTemp(false, kCoreReg);
+ int object_class = AllocTypedTemp(false, kCoreReg);
+
+ LoadCurrMethodDirect(check_class);
+ if (use_declaring_class) {
+ LoadWordDisp(check_class, mirror::AbstractMethod::DeclaringClassOffset().Int32Value(),
+ check_class);
+ LoadWordDisp(object.low_reg, mirror::Object::ClassOffset().Int32Value(), object_class);
+ } else {
+ LoadWordDisp(check_class, mirror::AbstractMethod::DexCacheResolvedTypesOffset().Int32Value(),
+ check_class);
+ LoadWordDisp(object.low_reg, mirror::Object::ClassOffset().Int32Value(), object_class);
+ int32_t offset_of_type =
+ mirror::Array::DataOffset(sizeof(mirror::Class*)).Int32Value() +
+ (sizeof(mirror::Class*) * type_idx);
+ LoadWordDisp(check_class, offset_of_type, check_class);
+ }
+
+ LIR* ne_branchover = NULL;
+ if (cu_->instruction_set == kThumb2) {
+ OpRegReg(kOpCmp, check_class, object_class); // Same?
+ OpIT(kCondEq, ""); // if-convert the test
+ LoadConstant(result_reg, 1); // .eq case - load true
+ } else {
+ ne_branchover = OpCmpBranch(kCondNe, check_class, object_class, NULL);
+ LoadConstant(result_reg, 1); // eq case - load true
+ }
+ LIR* target = NewLIR0(kPseudoTargetLabel);
+ null_branchover->target = target;
+ if (ne_branchover != NULL) {
+ ne_branchover->target = target;
+ }
+ FreeTemp(object_class);
+ FreeTemp(check_class);
+ if (IsTemp(result_reg)) {
+ OpRegCopy(rl_result.low_reg, result_reg);
+ FreeTemp(result_reg);
+ }
+ StoreValue(rl_dest, rl_result);
+}
+
+void Mir2Lir::GenInstanceofCallingHelper(bool needs_access_check, bool type_known_final,
+ bool type_known_abstract, bool use_declaring_class,
+ bool can_assume_type_is_in_dex_cache,
+ uint32_t type_idx, RegLocation rl_dest,
+ RegLocation rl_src) {
FlushAllRegs();
// May generate a call - use explicit registers
LockCallTemps();
LoadCurrMethodDirect(TargetReg(kArg1)); // kArg1 <= current Method*
int class_reg = TargetReg(kArg2); // kArg2 will hold the Class*
- if (!cu_->compiler_driver->CanAccessTypeWithoutChecks(cu_->method_idx,
- *cu_->dex_file,
- type_idx)) {
+ if (needs_access_check) {
// Check we have access to type_idx and if not throw IllegalAccessError,
// returns Class* in kArg0
CallRuntimeHelperImm(ENTRYPOINT_OFFSET(pInitializeTypeAndVerifyAccessFromCode),
type_idx, true);
OpRegCopy(class_reg, TargetReg(kRet0)); // Align usage with fast path
LoadValueDirectFixed(rl_src, TargetReg(kArg0)); // kArg0 <= ref
+ } else if (use_declaring_class) {
+ LoadValueDirectFixed(rl_src, TargetReg(kArg0)); // kArg0 <= ref
+ LoadWordDisp(TargetReg(kArg1),
+ mirror::AbstractMethod::DeclaringClassOffset().Int32Value(), class_reg);
} else {
// Load dex cache entry into class_reg (kArg2)
LoadValueDirectFixed(rl_src, TargetReg(kArg0)); // kArg0 <= ref
@@ -907,8 +967,7 @@ void Mir2Lir::GenInstanceof(uint32_t type_idx, RegLocation rl_dest,
mirror::Array::DataOffset(sizeof(mirror::Class*)).Int32Value() + (sizeof(mirror::Class*)
* type_idx);
LoadWordDisp(class_reg, offset_of_type, class_reg);
- if (!cu_->compiler_driver->CanAssumeTypeIsPresentInDexCache(
- *cu_->dex_file, type_idx)) {
+ if (!can_assume_type_is_in_dex_cache) {
// Need to test presence of type in dex cache at runtime
LIR* hop_branch = OpCmpImmBranch(kCondNe, class_reg, 0, NULL);
// Not resolved
@@ -924,65 +983,120 @@ void Mir2Lir::GenInstanceof(uint32_t type_idx, RegLocation rl_dest,
/* kArg0 is ref, kArg2 is class. If ref==null, use directly as bool result */
RegLocation rl_result = GetReturn(false);
if (cu_->instruction_set == kMips) {
- LoadConstant(rl_result.low_reg, 0); // store false result for if branch is taken
+ // On MIPS rArg0 != rl_result, place false in result if branch is taken.
+ LoadConstant(rl_result.low_reg, 0);
}
LIR* branch1 = OpCmpImmBranch(kCondEq, TargetReg(kArg0), 0, NULL);
+
/* load object->klass_ */
DCHECK_EQ(mirror::Object::ClassOffset().Int32Value(), 0);
LoadWordDisp(TargetReg(kArg0), mirror::Object::ClassOffset().Int32Value(), TargetReg(kArg1));
/* kArg0 is ref, kArg1 is ref->klass_, kArg2 is class */
- LIR* call_inst;
LIR* branchover = NULL;
- if (cu_->instruction_set == kThumb2) {
- /* Uses conditional nullification */
- int r_tgt = LoadHelper(ENTRYPOINT_OFFSET(pInstanceofNonTrivialFromCode));
- OpRegReg(kOpCmp, TargetReg(kArg1), TargetReg(kArg2)); // Same?
- OpIT(kCondEq, "EE"); // if-convert the test
- LoadConstant(TargetReg(kArg0), 1); // .eq case - load true
- OpRegCopy(TargetReg(kArg0), TargetReg(kArg2)); // .ne case - arg0 <= class
- call_inst = OpReg(kOpBlx, r_tgt); // .ne case: helper(class, ref->class)
- FreeTemp(r_tgt);
+ if (type_known_final) {
+ // rl_result == ref == null == 0.
+ if (cu_->instruction_set == kThumb2) {
+ OpRegReg(kOpCmp, TargetReg(kArg1), TargetReg(kArg2)); // Same?
+ OpIT(kCondEq, "E"); // if-convert the test
+ LoadConstant(rl_result.low_reg, 1); // .eq case - load true
+ LoadConstant(rl_result.low_reg, 0); // .ne case - load false
+ } else {
+ LoadConstant(rl_result.low_reg, 0); // ne case - load false
+ branchover = OpCmpBranch(kCondNe, TargetReg(kArg1), TargetReg(kArg2), NULL);
+ LoadConstant(rl_result.low_reg, 1); // eq case - load true
+ }
} else {
- /* Uses branchovers */
- LoadConstant(rl_result.low_reg, 1); // assume true
- branchover = OpCmpBranch(kCondEq, TargetReg(kArg1), TargetReg(kArg2), NULL);
- if (cu_->instruction_set != kX86) {
+ if (cu_->instruction_set == kThumb2) {
int r_tgt = LoadHelper(ENTRYPOINT_OFFSET(pInstanceofNonTrivialFromCode));
+ if (!type_known_abstract) {
+ /* Uses conditional nullification */
+ OpRegReg(kOpCmp, TargetReg(kArg1), TargetReg(kArg2)); // Same?
+ OpIT(kCondEq, "EE"); // if-convert the test
+ LoadConstant(TargetReg(kArg0), 1); // .eq case - load true
+ }
OpRegCopy(TargetReg(kArg0), TargetReg(kArg2)); // .ne case - arg0 <= class
- call_inst = OpReg(kOpBlx, r_tgt); // .ne case: helper(class, ref->class)
+ OpReg(kOpBlx, r_tgt); // .ne case: helper(class, ref->class)
FreeTemp(r_tgt);
} else {
- OpRegCopy(TargetReg(kArg0), TargetReg(kArg2));
- call_inst = OpThreadMem(kOpBlx, ENTRYPOINT_OFFSET(pInstanceofNonTrivialFromCode));
+ if (!type_known_abstract) {
+ /* Uses branchovers */
+ LoadConstant(rl_result.low_reg, 1); // assume true
+ branchover = OpCmpBranch(kCondEq, TargetReg(kArg1), TargetReg(kArg2), NULL);
+ }
+ if (cu_->instruction_set != kX86) {
+ int r_tgt = LoadHelper(ENTRYPOINT_OFFSET(pInstanceofNonTrivialFromCode));
+ OpRegCopy(TargetReg(kArg0), TargetReg(kArg2)); // .ne case - arg0 <= class
+ OpReg(kOpBlx, r_tgt); // .ne case: helper(class, ref->class)
+ FreeTemp(r_tgt);
+ } else {
+ OpRegCopy(TargetReg(kArg0), TargetReg(kArg2));
+ OpThreadMem(kOpBlx, ENTRYPOINT_OFFSET(pInstanceofNonTrivialFromCode));
+ }
}
}
- MarkSafepointPC(call_inst);
+ // TODO: only clobber when type isn't final?
ClobberCalleeSave();
/* branch targets here */
LIR* target = NewLIR0(kPseudoTargetLabel);
StoreValue(rl_dest, rl_result);
branch1->target = target;
- if (cu_->instruction_set != kThumb2) {
+ if (branchover != NULL) {
branchover->target = target;
}
}
-void Mir2Lir::GenCheckCast(uint32_t type_idx, RegLocation rl_src)
+void Mir2Lir::GenInstanceof(uint32_t type_idx, RegLocation rl_dest, RegLocation rl_src) {
+ bool type_known_final, type_known_abstract, use_declaring_class;
+ bool needs_access_check = !cu_->compiler_driver->CanAccessTypeWithoutChecks(cu_->method_idx,
+ *cu_->dex_file,
+ type_idx,
+ &type_known_final,
+ &type_known_abstract,
+ &use_declaring_class);
+ bool can_assume_type_is_in_dex_cache = !needs_access_check &&
+ cu_->compiler_driver->CanAssumeTypeIsPresentInDexCache(*cu_->dex_file, type_idx);
+
+ if ((use_declaring_class || can_assume_type_is_in_dex_cache) && type_known_final) {
+ GenInstanceofFinal(use_declaring_class, type_idx, rl_dest, rl_src);
+ } else {
+ GenInstanceofCallingHelper(needs_access_check, type_known_final, type_known_abstract,
+ use_declaring_class, can_assume_type_is_in_dex_cache,
+ type_idx, rl_dest, rl_src);
+ }
+}
+
+void Mir2Lir::GenCheckCast(uint32_t insn_idx, uint32_t type_idx, RegLocation rl_src)
{
+ bool type_known_final, type_known_abstract, use_declaring_class;
+ bool needs_access_check = !cu_->compiler_driver->CanAccessTypeWithoutChecks(cu_->method_idx,
+ *cu_->dex_file,
+ type_idx,
+ &type_known_final,
+ &type_known_abstract,
+ &use_declaring_class);
+ // Note: currently type_known_final is unused, as optimizing will only improve the performance
+ // of the exception throw path.
+ DexCompilationUnit* cu = mir_graph_->GetCurrentDexCompilationUnit();
+ const CompilerDriver::MethodReference mr(cu->GetDexFile(), cu->GetDexMethodIndex());
+ if (!needs_access_check && cu_->compiler_driver->IsSafeCast(mr, insn_idx)) {
+ // Verifier type analysis proved this check cast would never cause an exception.
+ return;
+ }
FlushAllRegs();
// May generate a call - use explicit registers
LockCallTemps();
LoadCurrMethodDirect(TargetReg(kArg1)); // kArg1 <= current Method*
int class_reg = TargetReg(kArg2); // kArg2 will hold the Class*
- if (!cu_->compiler_driver->CanAccessTypeWithoutChecks(cu_->method_idx,
- *cu_->dex_file,
- type_idx)) {
+ if (needs_access_check) {
// Check we have access to type_idx and if not throw IllegalAccessError,
// returns Class* in kRet0
// InitializeTypeAndVerifyAccess(idx, method)
CallRuntimeHelperImmReg(ENTRYPOINT_OFFSET(pInitializeTypeAndVerifyAccessFromCode),
type_idx, TargetReg(kArg1), true);
OpRegCopy(class_reg, TargetReg(kRet0)); // Align usage with fast path
+ } else if (use_declaring_class) {
+ LoadWordDisp(TargetReg(kArg1),
+ mirror::AbstractMethod::DeclaringClassOffset().Int32Value(), class_reg);
} else {
// Load dex cache entry into class_reg (kArg2)
LoadWordDisp(TargetReg(kArg1),
@@ -991,8 +1105,7 @@ void Mir2Lir::GenCheckCast(uint32_t type_idx, RegLocation rl_src)
mirror::Array::DataOffset(sizeof(mirror::Class*)).Int32Value() +
(sizeof(mirror::Class*) * type_idx);
LoadWordDisp(class_reg, offset_of_type, class_reg);
- if (!cu_->compiler_driver->CanAssumeTypeIsPresentInDexCache(
- *cu_->dex_file, type_idx)) {
+ if (!cu_->compiler_driver->CanAssumeTypeIsPresentInDexCache(*cu_->dex_file, type_idx)) {
// Need to test presence of type in dex cache at runtime
LIR* hop_branch = OpCmpImmBranch(kCondNe, class_reg, 0, NULL);
// Not resolved
@@ -1014,25 +1127,18 @@ void Mir2Lir::GenCheckCast(uint32_t type_idx, RegLocation rl_src)
DCHECK_EQ(mirror::Object::ClassOffset().Int32Value(), 0);
LoadWordDisp(TargetReg(kArg0), mirror::Object::ClassOffset().Int32Value(), TargetReg(kArg1));
/* kArg1 now contains object->klass_ */
- LIR* branch2;
- if (cu_->instruction_set == kThumb2) {
- int r_tgt = LoadHelper(ENTRYPOINT_OFFSET(pCheckCastFromCode));
- OpRegReg(kOpCmp, TargetReg(kArg1), class_reg);
- branch2 = OpCondBranch(kCondEq, NULL); /* If eq, trivial yes */
- OpRegCopy(TargetReg(kArg0), TargetReg(kArg1));
- OpRegCopy(TargetReg(kArg1), TargetReg(kArg2));
- ClobberCalleeSave();
- LIR* call_inst = OpReg(kOpBlx, r_tgt);
- MarkSafepointPC(call_inst);
- FreeTemp(r_tgt);
- } else {
+ LIR* branch2 = NULL;
+ if (!type_known_abstract) {
branch2 = OpCmpBranch(kCondEq, TargetReg(kArg1), class_reg, NULL);
- CallRuntimeHelperRegReg(ENTRYPOINT_OFFSET(pCheckCastFromCode), TargetReg(kArg1), TargetReg(kArg2), true);
}
+ CallRuntimeHelperRegReg(ENTRYPOINT_OFFSET(pCheckCastFromCode), TargetReg(kArg1), TargetReg(kArg2),
+ true);
/* branch target here */
LIR* target = NewLIR0(kPseudoTargetLabel);
branch1->target = target;
- branch2->target = target;
+ if (branch2 != NULL) {
+ branch2->target = target;
+ }
}
void Mir2Lir::GenLong3Addr(OpKind first_op, OpKind second_op, RegLocation rl_dest,
diff --git a/src/compiler/dex/quick/gen_invoke.cc b/src/compiler/dex/quick/gen_invoke.cc
index afcd9efb7d..4b12bb407a 100644
--- a/src/compiler/dex/quick/gen_invoke.cc
+++ b/src/compiler/dex/quick/gen_invoke.cc
@@ -15,9 +15,11 @@
*/
#include "compiler/dex/compiler_ir.h"
+#include "dex_file-inl.h"
#include "invoke_type.h"
#include "mirror/array.h"
#include "mirror/string.h"
+#include "mir_to_lir-inl.h"
#include "oat/runtime/oat_support_entrypoints.h"
#include "x86/codegen_x86.h"
@@ -311,7 +313,8 @@ void Mir2Lir::FlushIns(RegLocation* ArgLocs, RegLocation rl_method)
* emit the next instruction in static & direct invoke sequences.
*/
static int NextSDCallInsn(CompilationUnit* cu, CallInfo* info,
- int state, uint32_t dex_idx, uint32_t unused,
+ int state, const CompilerDriver::MethodReference& target_method,
+ uint32_t unused,
uintptr_t direct_code, uintptr_t direct_method,
InvokeType type)
{
@@ -327,9 +330,11 @@ static int NextSDCallInsn(CompilationUnit* cu, CallInfo* info,
if (direct_code != static_cast<unsigned int>(-1)) {
cg->LoadConstant(cg->TargetReg(kInvokeTgt), direct_code);
} else {
- LIR* data_target = cg->ScanLiteralPool(cg->code_literal_list_, dex_idx, 0);
+ CHECK_EQ(cu->dex_file, target_method.dex_file);
+ LIR* data_target = cg->ScanLiteralPool(cg->code_literal_list_,
+ target_method.dex_method_index, 0);
if (data_target == NULL) {
- data_target = cg->AddWordData(&cg->code_literal_list_, dex_idx);
+ data_target = cg->AddWordData(&cg->code_literal_list_, target_method.dex_method_index);
data_target->operands[1] = type;
}
LIR* load_pc_rel = cg->OpPcRelLoad(cg->TargetReg(kInvokeTgt), data_target);
@@ -339,9 +344,11 @@ static int NextSDCallInsn(CompilationUnit* cu, CallInfo* info,
if (direct_method != static_cast<unsigned int>(-1)) {
cg->LoadConstant(cg->TargetReg(kArg0), direct_method);
} else {
- LIR* data_target = cg->ScanLiteralPool(cg->method_literal_list_, dex_idx, 0);
+ CHECK_EQ(cu->dex_file, target_method.dex_file);
+ LIR* data_target = cg->ScanLiteralPool(cg->method_literal_list_,
+ target_method.dex_method_index, 0);
if (data_target == NULL) {
- data_target = cg->AddWordData(&cg->method_literal_list_, dex_idx);
+ data_target = cg->AddWordData(&cg->method_literal_list_, target_method.dex_method_index);
data_target->operands[1] = type;
}
LIR* load_pc_rel = cg->OpPcRelLoad(cg->TargetReg(kArg0), data_target);
@@ -366,9 +373,11 @@ static int NextSDCallInsn(CompilationUnit* cu, CallInfo* info,
if (direct_code != static_cast<unsigned int>(-1)) {
cg->LoadConstant(cg->TargetReg(kInvokeTgt), direct_code);
} else {
- LIR* data_target = cg->ScanLiteralPool(cg->code_literal_list_, dex_idx, 0);
+ CHECK_EQ(cu->dex_file, target_method.dex_file);
+ LIR* data_target = cg->ScanLiteralPool(cg->code_literal_list_,
+ target_method.dex_method_index, 0);
if (data_target == NULL) {
- data_target = cg->AddWordData(&cg->code_literal_list_, dex_idx);
+ data_target = cg->AddWordData(&cg->code_literal_list_, target_method.dex_method_index);
data_target->operands[1] = type;
}
LIR* load_pc_rel = cg->OpPcRelLoad(cg->TargetReg(kInvokeTgt), data_target);
@@ -378,8 +387,10 @@ static int NextSDCallInsn(CompilationUnit* cu, CallInfo* info,
}
break;
case 2: // Grab target method*
+ CHECK_EQ(cu->dex_file, target_method.dex_file);
cg->LoadWordDisp(cg->TargetReg(kArg0),
- mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() + dex_idx * 4,
+ mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() +
+ (target_method.dex_method_index * 4),
cg-> TargetReg(kArg0));
break;
case 3: // Grab the code from the method*
@@ -407,8 +418,9 @@ static int NextSDCallInsn(CompilationUnit* cu, CallInfo* info,
* kArg1 here rather than the standard LoadArgRegs.
*/
static int NextVCallInsn(CompilationUnit* cu, CallInfo* info,
- int state, uint32_t dex_idx, uint32_t method_idx,
- uintptr_t unused, uintptr_t unused2, InvokeType unused3)
+ int state, const CompilerDriver::MethodReference& target_method,
+ uint32_t method_idx, uintptr_t unused, uintptr_t unused2,
+ InvokeType unused3)
{
Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get());
/*
@@ -455,7 +467,8 @@ static int NextVCallInsn(CompilationUnit* cu, CallInfo* info,
* which will locate the target and continue on via a tail call.
*/
static int NextInterfaceCallInsn(CompilationUnit* cu, CallInfo* info, int state,
- uint32_t dex_idx, uint32_t unused, uintptr_t unused2,
+ const CompilerDriver::MethodReference& target_method,
+ uint32_t unused, uintptr_t unused2,
uintptr_t direct_method, InvokeType unused4)
{
Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get());
@@ -476,9 +489,12 @@ static int NextInterfaceCallInsn(CompilationUnit* cu, CallInfo* info, int state,
if (direct_method != static_cast<unsigned int>(-1)) {
cg->LoadConstant(cg->TargetReg(kArg0), direct_method);
} else {
- LIR* data_target = cg->ScanLiteralPool(cg->method_literal_list_, dex_idx, 0);
+ CHECK_EQ(cu->dex_file, target_method.dex_file);
+ LIR* data_target = cg->ScanLiteralPool(cg->method_literal_list_,
+ target_method.dex_method_index, 0);
if (data_target == NULL) {
- data_target = cg->AddWordData(&cg->method_literal_list_, dex_idx);
+ data_target = cg->AddWordData(&cg->method_literal_list_,
+ target_method.dex_method_index);
data_target->operands[1] = kInterface;
}
LIR* load_pc_rel = cg->OpPcRelLoad(cg->TargetReg(kArg0), data_target);
@@ -505,8 +521,10 @@ static int NextInterfaceCallInsn(CompilationUnit* cu, CallInfo* info, int state,
cg->TargetReg(kArg0));
break;
case 2: // Grab target method* [set/use kArg0]
+ CHECK_EQ(cu->dex_file, target_method.dex_file);
cg->LoadWordDisp(cg->TargetReg(kArg0),
- mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() + dex_idx * 4,
+ mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() +
+ (target_method.dex_method_index * 4),
cg->TargetReg(kArg0));
break;
default:
@@ -517,7 +535,8 @@ static int NextInterfaceCallInsn(CompilationUnit* cu, CallInfo* info, int state,
}
static int NextInvokeInsnSP(CompilationUnit* cu, CallInfo* info, int trampoline,
- int state, uint32_t dex_idx, uint32_t method_idx)
+ int state, const CompilerDriver::MethodReference& target_method,
+ uint32_t method_idx)
{
Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get());
/*
@@ -530,58 +549,66 @@ static int NextInvokeInsnSP(CompilationUnit* cu, CallInfo* info, int trampoline,
cg->LoadWordDisp(cg->TargetReg(kSelf), trampoline, cg->TargetReg(kInvokeTgt));
}
// Load kArg0 with method index
- cg->LoadConstant(cg->TargetReg(kArg0), dex_idx);
+ CHECK_EQ(cu->dex_file, target_method.dex_file);
+ cg->LoadConstant(cg->TargetReg(kArg0), target_method.dex_method_index);
return 1;
}
return -1;
}
static int NextStaticCallInsnSP(CompilationUnit* cu, CallInfo* info,
- int state, uint32_t dex_idx, uint32_t method_idx,
+ int state,
+ const CompilerDriver::MethodReference& target_method,
+ uint32_t method_idx,
uintptr_t unused, uintptr_t unused2,
- InvokeType unused3)
+ InvokeType unused3)
{
int trampoline = ENTRYPOINT_OFFSET(pInvokeStaticTrampolineWithAccessCheck);
- return NextInvokeInsnSP(cu, info, trampoline, state, dex_idx, 0);
+ return NextInvokeInsnSP(cu, info, trampoline, state, target_method, 0);
}
static int NextDirectCallInsnSP(CompilationUnit* cu, CallInfo* info, int state,
- uint32_t dex_idx, uint32_t method_idx, uintptr_t unused,
+ const CompilerDriver::MethodReference& target_method,
+ uint32_t method_idx, uintptr_t unused,
uintptr_t unused2, InvokeType unused3)
{
int trampoline = ENTRYPOINT_OFFSET(pInvokeDirectTrampolineWithAccessCheck);
- return NextInvokeInsnSP(cu, info, trampoline, state, dex_idx, 0);
+ return NextInvokeInsnSP(cu, info, trampoline, state, target_method, 0);
}
static int NextSuperCallInsnSP(CompilationUnit* cu, CallInfo* info, int state,
- uint32_t dex_idx, uint32_t method_idx, uintptr_t unused,
- uintptr_t unused2, InvokeType unused3)
+ const CompilerDriver::MethodReference& target_method,
+ uint32_t method_idx, uintptr_t unused,
+ uintptr_t unused2, InvokeType unused3)
{
int trampoline = ENTRYPOINT_OFFSET(pInvokeSuperTrampolineWithAccessCheck);
- return NextInvokeInsnSP(cu, info, trampoline, state, dex_idx, 0);
+ return NextInvokeInsnSP(cu, info, trampoline, state, target_method, 0);
}
static int NextVCallInsnSP(CompilationUnit* cu, CallInfo* info, int state,
- uint32_t dex_idx, uint32_t method_idx, uintptr_t unused,
+ const CompilerDriver::MethodReference& target_method,
+ uint32_t method_idx, uintptr_t unused,
uintptr_t unused2, InvokeType unused3)
{
int trampoline = ENTRYPOINT_OFFSET(pInvokeVirtualTrampolineWithAccessCheck);
- return NextInvokeInsnSP(cu, info, trampoline, state, dex_idx, 0);
+ return NextInvokeInsnSP(cu, info, trampoline, state, target_method, 0);
}
static int NextInterfaceCallInsnWithAccessCheck(CompilationUnit* cu,
CallInfo* info, int state,
- uint32_t dex_idx, uint32_t unused,
- uintptr_t unused2, uintptr_t unused3,
- InvokeType unused4)
+ const CompilerDriver::MethodReference& target_method,
+ uint32_t unused,
+ uintptr_t unused2, uintptr_t unused3,
+ InvokeType unused4)
{
int trampoline = ENTRYPOINT_OFFSET(pInvokeInterfaceTrampolineWithAccessCheck);
- return NextInvokeInsnSP(cu, info, trampoline, state, dex_idx, 0);
+ return NextInvokeInsnSP(cu, info, trampoline, state, target_method, 0);
}
int Mir2Lir::LoadArgRegs(CallInfo* info, int call_state,
- NextCallInsn next_call_insn, uint32_t dex_idx,
- uint32_t method_idx, uintptr_t direct_code,
+ NextCallInsn next_call_insn,
+ const CompilerDriver::MethodReference& target_method,
+ uint32_t vtable_idx, uintptr_t direct_code,
uintptr_t direct_method, InvokeType type, bool skip_this)
{
int last_arg_reg = TargetReg(kArg3);
@@ -605,8 +632,8 @@ int Mir2Lir::LoadArgRegs(CallInfo* info, int call_state,
}
LoadValueDirectFixed(rl_arg, next_reg);
}
- call_state = next_call_insn(cu_, info, call_state, dex_idx, method_idx,
- direct_code, direct_method, type);
+ call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
+ direct_code, direct_method, type);
}
return call_state;
}
@@ -620,7 +647,8 @@ int Mir2Lir::LoadArgRegs(CallInfo* info, int call_state,
*/
int Mir2Lir::GenDalvikArgsNoRange(CallInfo* info,
int call_state, LIR** pcrLabel, NextCallInsn next_call_insn,
- uint32_t dex_idx, uint32_t method_idx, uintptr_t direct_code,
+ const CompilerDriver::MethodReference& target_method,
+ uint32_t vtable_idx, uintptr_t direct_code,
uintptr_t direct_method, InvokeType type, bool skip_this)
{
RegLocation rl_arg;
@@ -629,8 +657,8 @@ int Mir2Lir::GenDalvikArgsNoRange(CallInfo* info,
if (info->num_arg_words == 0)
return call_state;
- call_state = next_call_insn(cu_, info, call_state, dex_idx, method_idx,
- direct_code, direct_method, type);
+ call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
+ direct_code, direct_method, type);
DCHECK_LE(info->num_arg_words, 5);
if (info->num_arg_words > 3) {
@@ -650,13 +678,13 @@ int Mir2Lir::GenDalvikArgsNoRange(CallInfo* info,
// kArg2 & rArg3 can safely be used here
reg = TargetReg(kArg3);
LoadWordDisp(TargetReg(kSp), SRegOffset(rl_arg.s_reg_low) + 4, reg);
- call_state = next_call_insn(cu_, info, call_state, dex_idx,
- method_idx, direct_code, direct_method, type);
+ call_state = next_call_insn(cu_, info, call_state, target_method,
+ vtable_idx, direct_code, direct_method, type);
}
StoreBaseDisp(TargetReg(kSp), (next_use + 1) * 4, reg, kWord);
StoreBaseDisp(TargetReg(kSp), 16 /* (3+1)*4 */, reg, kWord);
- call_state = next_call_insn(cu_, info, call_state, dex_idx, method_idx,
- direct_code, direct_method, type);
+ call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
+ direct_code, direct_method, type);
next_use++;
}
// Loop through the rest
@@ -676,8 +704,8 @@ int Mir2Lir::GenDalvikArgsNoRange(CallInfo* info,
} else {
LoadValueDirectFixed(rl_arg, low_reg);
}
- call_state = next_call_insn(cu_, info, call_state, dex_idx,
- method_idx, direct_code, direct_method, type);
+ call_state = next_call_insn(cu_, info, call_state, target_method,
+ vtable_idx, direct_code, direct_method, type);
}
int outs_offset = (next_use + 1) * 4;
if (rl_arg.wide) {
@@ -687,14 +715,14 @@ int Mir2Lir::GenDalvikArgsNoRange(CallInfo* info,
StoreWordDisp(TargetReg(kSp), outs_offset, low_reg);
next_use++;
}
- call_state = next_call_insn(cu_, info, call_state, dex_idx, method_idx,
+ call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
direct_code, direct_method, type);
}
}
call_state = LoadArgRegs(info, call_state, next_call_insn,
- dex_idx, method_idx, direct_code, direct_method,
- type, skip_this);
+ target_method, vtable_idx, direct_code, direct_method,
+ type, skip_this);
if (pcrLabel) {
*pcrLabel = GenNullCheck(info->args[0].s_reg_low, TargetReg(kArg1), info->opt_flags);
@@ -718,15 +746,16 @@ int Mir2Lir::GenDalvikArgsNoRange(CallInfo* info,
*
*/
int Mir2Lir::GenDalvikArgsRange(CallInfo* info, int call_state,
- LIR** pcrLabel, NextCallInsn next_call_insn, uint32_t dex_idx,
- uint32_t method_idx, uintptr_t direct_code, uintptr_t direct_method,
+ LIR** pcrLabel, NextCallInsn next_call_insn,
+ const CompilerDriver::MethodReference& target_method,
+ uint32_t vtable_idx, uintptr_t direct_code, uintptr_t direct_method,
InvokeType type, bool skip_this)
{
// If we can treat it as non-range (Jumbo ops will use range form)
if (info->num_arg_words <= 5)
return GenDalvikArgsNoRange(info, call_state, pcrLabel,
- next_call_insn, dex_idx, method_idx,
+ next_call_insn, target_method, vtable_idx,
direct_code, direct_method, type, skip_this);
/*
* First load the non-register arguments. Both forms expect all
@@ -772,31 +801,31 @@ int Mir2Lir::GenDalvikArgsRange(CallInfo* info, int call_state,
} else {
// Use vldm/vstm pair using kArg3 as a temp
int regs_left = std::min(info->num_arg_words - 3, 16);
- call_state = next_call_insn(cu_, info, call_state, dex_idx, method_idx,
+ call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
direct_code, direct_method, type);
OpRegRegImm(kOpAdd, TargetReg(kArg3), TargetReg(kSp), start_offset);
LIR* ld = OpVldm(TargetReg(kArg3), regs_left);
//TUNING: loosen barrier
ld->def_mask = ENCODE_ALL;
SetMemRefType(ld, true /* is_load */, kDalvikReg);
- call_state = next_call_insn(cu_, info, call_state, dex_idx, method_idx,
+ call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
direct_code, direct_method, type);
OpRegRegImm(kOpAdd, TargetReg(kArg3), TargetReg(kSp), 4 /* Method* */ + (3 * 4));
- call_state = next_call_insn(cu_, info, call_state, dex_idx, method_idx,
+ call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
direct_code, direct_method, type);
LIR* st = OpVstm(TargetReg(kArg3), regs_left);
SetMemRefType(st, false /* is_load */, kDalvikReg);
st->def_mask = ENCODE_ALL;
- call_state = next_call_insn(cu_, info, call_state, dex_idx, method_idx,
+ call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
direct_code, direct_method, type);
}
}
call_state = LoadArgRegs(info, call_state, next_call_insn,
- dex_idx, method_idx, direct_code, direct_method,
- type, skip_this);
+ target_method, vtable_idx, direct_code, direct_method,
+ type, skip_this);
- call_state = next_call_insn(cu_, info, call_state, dex_idx, method_idx,
+ call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
direct_code, direct_method, type);
if (pcrLabel) {
*pcrLabel = GenNullCheck(info->args[0].s_reg_low, TargetReg(kArg1), info->opt_flags);
@@ -1150,6 +1179,10 @@ bool Mir2Lir::GenInlinedUnsafePut(CallInfo* info, bool is_long,
// TODO - add Mips implementation
return false;
}
+ if (cu_->instruction_set == kX86 && is_object) {
+ // TODO: fix X86, it exhausts registers for card marking.
+ return false;
+ }
// Unused - RegLocation rl_src_unsafe = info->args[0];
RegLocation rl_src_obj = info->args[1]; // Object
RegLocation rl_src_offset = info->args[2]; // long low
@@ -1193,20 +1226,27 @@ bool Mir2Lir::GenIntrinsic(CallInfo* info)
* method. By doing this during basic block construction, we can also
* take advantage of/generate new useful dataflow info.
*/
- std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file));
- if (tgt_method.find(" java.lang") != std::string::npos) {
+ StringPiece tgt_methods_declaring_class(
+ cu_->dex_file->GetMethodDeclaringClassDescriptor(cu_->dex_file->GetMethodId(info->index)));
+ if (tgt_methods_declaring_class.starts_with("Ljava/lang/Double;")) {
+ std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file));
if (tgt_method == "long java.lang.Double.doubleToRawLongBits(double)") {
return GenInlinedDoubleCvt(info);
}
if (tgt_method == "double java.lang.Double.longBitsToDouble(long)") {
return GenInlinedDoubleCvt(info);
}
+ } else if (tgt_methods_declaring_class.starts_with("Ljava/lang/Float;")) {
+ std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file));
if (tgt_method == "int java.lang.Float.float_to_raw_int_bits(float)") {
return GenInlinedFloatCvt(info);
}
if (tgt_method == "float java.lang.Float.intBitsToFloat(int)") {
return GenInlinedFloatCvt(info);
}
+ } else if (tgt_methods_declaring_class.starts_with("Ljava/lang/Math;") ||
+ tgt_methods_declaring_class.starts_with("Ljava/lang/StrictMath;")) {
+ std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file));
if (tgt_method == "int java.lang.Math.abs(int)" ||
tgt_method == "int java.lang.StrictMath.abs(int)") {
return GenInlinedAbsInt(info);
@@ -1227,6 +1267,8 @@ bool Mir2Lir::GenIntrinsic(CallInfo* info)
tgt_method == "double java.lang.StrictMath.sqrt(double)") {
return GenInlinedSqrt(info);
}
+ } else if (tgt_methods_declaring_class.starts_with("Ljava/lang/String;")) {
+ std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file));
if (tgt_method == "char java.lang.String.charAt(int)") {
return GenInlinedCharAt(info);
}
@@ -1245,10 +1287,13 @@ bool Mir2Lir::GenIntrinsic(CallInfo* info)
if (tgt_method == "int java.lang.String.length()") {
return GenInlinedStringIsEmptyOrLength(info, false /* is_empty */);
}
+ } else if (tgt_methods_declaring_class.starts_with("Ljava/lang/Thread;")) {
+ std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file));
if (tgt_method == "java.lang.Thread java.lang.Thread.currentThread()") {
return GenInlinedCurrentThread(info);
}
- } else if (tgt_method.find(" sun.misc.Unsafe") != std::string::npos) {
+ } else if (tgt_methods_declaring_class.starts_with("Lsun/misc/Unsafe;")) {
+ std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file));
if (tgt_method == "boolean sun.misc.Unsafe.compareAndSwapInt(java.lang.Object, long, int, int)") {
return GenInlinedCas32(info, false);
}
@@ -1327,20 +1372,24 @@ void Mir2Lir::GenInvoke(CallInfo* info)
// Explicit register usage
LockCallTemps();
- uint32_t dex_method_idx = info->index;
+ DexCompilationUnit* cUnit = mir_graph_->GetCurrentDexCompilationUnit();
+ CompilerDriver::MethodReference target_method(cUnit->GetDexFile(), info->index);
int vtable_idx;
uintptr_t direct_code;
uintptr_t direct_method;
bool skip_this;
- bool fast_path = cu_->compiler_driver->ComputeInvokeInfo(
- dex_method_idx, current_dalvik_offset_, mir_graph_->GetCurrentDexCompilationUnit(), info->type, vtable_idx,
- direct_code, direct_method) && !SLOW_INVOKE_PATH;
+ bool fast_path =
+ cu_->compiler_driver->ComputeInvokeInfo(mir_graph_->GetCurrentDexCompilationUnit(),
+ current_dalvik_offset_,
+ info->type, target_method,
+ vtable_idx,
+ direct_code, direct_method,
+ true) && !SLOW_INVOKE_PATH;
if (info->type == kInterface) {
if (fast_path) {
p_null_ck = &null_ck;
}
- next_call_insn = fast_path ? NextInterfaceCallInsn
- : NextInterfaceCallInsnWithAccessCheck;
+ next_call_insn = fast_path ? NextInterfaceCallInsn : NextInterfaceCallInsnWithAccessCheck;
skip_this = false;
} else if (info->type == kDirect) {
if (fast_path) {
@@ -1362,20 +1411,20 @@ void Mir2Lir::GenInvoke(CallInfo* info)
}
if (!info->is_range) {
call_state = GenDalvikArgsNoRange(info, call_state, p_null_ck,
- next_call_insn, dex_method_idx,
- vtable_idx, direct_code, direct_method,
- original_type, skip_this);
+ next_call_insn, target_method,
+ vtable_idx, direct_code, direct_method,
+ original_type, skip_this);
} else {
call_state = GenDalvikArgsRange(info, call_state, p_null_ck,
- next_call_insn, dex_method_idx, vtable_idx,
- direct_code, direct_method, original_type,
- skip_this);
+ next_call_insn, target_method, vtable_idx,
+ direct_code, direct_method, original_type,
+ skip_this);
}
// Finish up any of the call sequence not interleaved in arg loading
while (call_state >= 0) {
- call_state = next_call_insn(cu_, info, call_state, dex_method_idx,
- vtable_idx, direct_code, direct_method,
- original_type);
+ call_state = next_call_insn(cu_, info, call_state, target_method,
+ vtable_idx, direct_code, direct_method,
+ original_type);
}
LIR* call_inst;
if (cu_->instruction_set != kX86) {
diff --git a/src/compiler/dex/quick/gen_loadstore.cc b/src/compiler/dex/quick/gen_loadstore.cc
index 1cebd31d19..085f7f518c 100644
--- a/src/compiler/dex/quick/gen_loadstore.cc
+++ b/src/compiler/dex/quick/gen_loadstore.cc
@@ -16,6 +16,7 @@
#include "compiler/dex/compiler_ir.h"
#include "compiler/dex/compiler_internals.h"
+#include "compiler/dex/quick/mir_to_lir-inl.h"
#include "invoke_type.h"
namespace art {
diff --git a/src/compiler/dex/quick/mips/assemble_mips.cc b/src/compiler/dex/quick/mips/assemble_mips.cc
index 5223a0ecfd..002a23e5ae 100644
--- a/src/compiler/dex/quick/mips/assemble_mips.cc
+++ b/src/compiler/dex/quick/mips/assemble_mips.cc
@@ -15,6 +15,7 @@
*/
#include "codegen_mips.h"
+#include "compiler/dex/quick/mir_to_lir-inl.h"
#include "mips_lir.h"
namespace art {
diff --git a/src/compiler/dex/quick/mips/call_mips.cc b/src/compiler/dex/quick/mips/call_mips.cc
index b53d1e35a5..ddaf08156a 100644
--- a/src/compiler/dex/quick/mips/call_mips.cc
+++ b/src/compiler/dex/quick/mips/call_mips.cc
@@ -17,6 +17,7 @@
/* This file contains codegen for the Mips ISA */
#include "codegen_mips.h"
+#include "compiler/dex/quick/mir_to_lir-inl.h"
#include "mips_lir.h"
#include "oat/runtime/oat_support_entrypoints.h"
@@ -319,7 +320,7 @@ void MipsMir2Lir::MarkGCCard(int val_reg, int tgt_addr_reg)
int reg_card_no = AllocTemp();
LIR* branch_over = OpCmpImmBranch(kCondEq, val_reg, 0, NULL);
LoadWordDisp(rMIPS_SELF, Thread::CardTableOffset().Int32Value(), reg_card_base);
- OpRegRegImm(kOpLsr, reg_card_no, tgt_addr_reg, CardTable::kCardShift);
+ OpRegRegImm(kOpLsr, reg_card_no, tgt_addr_reg, gc::accounting::CardTable::kCardShift);
StoreBaseIndexed(reg_card_base, reg_card_no, reg_card_base, 0,
kUnsignedByte);
LIR* target = NewLIR0(kPseudoTargetLabel);
diff --git a/src/compiler/dex/quick/mips/codegen_mips.h b/src/compiler/dex/quick/mips/codegen_mips.h
index db262a8e96..9fa8f779fe 100644
--- a/src/compiler/dex/quick/mips/codegen_mips.h
+++ b/src/compiler/dex/quick/mips/codegen_mips.h
@@ -28,139 +28,139 @@ class MipsMir2Lir : public Mir2Lir {
MipsMir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena);
// Required for target - codegen utilities.
- virtual bool SmallLiteralDivide(Instruction::Code dalvik_opcode, RegLocation rl_src,
+ bool SmallLiteralDivide(Instruction::Code dalvik_opcode, RegLocation rl_src,
RegLocation rl_dest, int lit);
- virtual int LoadHelper(int offset);
- virtual LIR* LoadBaseDisp(int rBase, int displacement, int r_dest, OpSize size, int s_reg);
- virtual LIR* LoadBaseDispWide(int rBase, int displacement, int r_dest_lo, int r_dest_hi,
+ int LoadHelper(int offset);
+ LIR* LoadBaseDisp(int rBase, int displacement, int r_dest, OpSize size, int s_reg);
+ LIR* LoadBaseDispWide(int rBase, int displacement, int r_dest_lo, int r_dest_hi,
int s_reg);
- virtual LIR* LoadBaseIndexed(int rBase, int r_index, int r_dest, int scale, OpSize size);
- virtual LIR* LoadBaseIndexedDisp(int rBase, int r_index, int scale, int displacement,
+ LIR* LoadBaseIndexed(int rBase, int r_index, int r_dest, int scale, OpSize size);
+ LIR* LoadBaseIndexedDisp(int rBase, int r_index, int scale, int displacement,
int r_dest, int r_dest_hi, OpSize size, int s_reg);
- virtual LIR* LoadConstantNoClobber(int r_dest, int value);
- virtual LIR* LoadConstantWide(int r_dest_lo, int r_dest_hi, int64_t value);
- virtual LIR* StoreBaseDisp(int rBase, int displacement, int r_src, OpSize size);
- virtual LIR* StoreBaseDispWide(int rBase, int displacement, int r_src_lo, int r_src_hi);
- virtual LIR* StoreBaseIndexed(int rBase, int r_index, int r_src, int scale, OpSize size);
- virtual LIR* StoreBaseIndexedDisp(int rBase, int r_index, int scale, int displacement,
+ LIR* LoadConstantNoClobber(int r_dest, int value);
+ LIR* LoadConstantWide(int r_dest_lo, int r_dest_hi, int64_t value);
+ LIR* StoreBaseDisp(int rBase, int displacement, int r_src, OpSize size);
+ LIR* StoreBaseDispWide(int rBase, int displacement, int r_src_lo, int r_src_hi);
+ LIR* StoreBaseIndexed(int rBase, int r_index, int r_src, int scale, OpSize size);
+ LIR* StoreBaseIndexedDisp(int rBase, int r_index, int scale, int displacement,
int r_src, int r_src_hi, OpSize size, int s_reg);
- virtual void MarkGCCard(int val_reg, int tgt_addr_reg);
+ void MarkGCCard(int val_reg, int tgt_addr_reg);
// Required for target - register utilities.
- virtual bool IsFpReg(int reg);
- virtual bool SameRegType(int reg1, int reg2);
- virtual int AllocTypedTemp(bool fp_hint, int reg_class);
- virtual int AllocTypedTempPair(bool fp_hint, int reg_class);
- virtual int S2d(int low_reg, int high_reg);
- virtual int TargetReg(SpecialTargetRegister reg);
- virtual RegisterInfo* GetRegInfo(int reg);
- virtual RegLocation GetReturnAlt();
- virtual RegLocation GetReturnWideAlt();
- virtual RegLocation LocCReturn();
- virtual RegLocation LocCReturnDouble();
- virtual RegLocation LocCReturnFloat();
- virtual RegLocation LocCReturnWide();
- virtual uint32_t FpRegMask();
- virtual uint64_t GetRegMaskCommon(int reg);
- virtual void AdjustSpillMask();
- virtual void ClobberCalleeSave();
- virtual void FlushReg(int reg);
- virtual void FlushRegWide(int reg1, int reg2);
- virtual void FreeCallTemps();
- virtual void FreeRegLocTemps(RegLocation rl_keep, RegLocation rl_free);
- virtual void LockCallTemps();
- virtual void MarkPreservedSingle(int v_reg, int reg);
- virtual void CompilerInitializeRegAlloc();
+ bool IsFpReg(int reg);
+ bool SameRegType(int reg1, int reg2);
+ int AllocTypedTemp(bool fp_hint, int reg_class);
+ int AllocTypedTempPair(bool fp_hint, int reg_class);
+ int S2d(int low_reg, int high_reg);
+ int TargetReg(SpecialTargetRegister reg);
+ RegisterInfo* GetRegInfo(int reg);
+ RegLocation GetReturnAlt();
+ RegLocation GetReturnWideAlt();
+ RegLocation LocCReturn();
+ RegLocation LocCReturnDouble();
+ RegLocation LocCReturnFloat();
+ RegLocation LocCReturnWide();
+ uint32_t FpRegMask();
+ uint64_t GetRegMaskCommon(int reg);
+ void AdjustSpillMask();
+ void ClobberCalleeSave();
+ void FlushReg(int reg);
+ void FlushRegWide(int reg1, int reg2);
+ void FreeCallTemps();
+ void FreeRegLocTemps(RegLocation rl_keep, RegLocation rl_free);
+ void LockCallTemps();
+ void MarkPreservedSingle(int v_reg, int reg);
+ void CompilerInitializeRegAlloc();
// Required for target - miscellaneous.
- virtual AssemblerStatus AssembleInstructions(uintptr_t start_addr);
- virtual void DumpResourceMask(LIR* lir, uint64_t mask, const char* prefix);
- virtual void SetupTargetResourceMasks(LIR* lir);
- virtual const char* GetTargetInstFmt(int opcode);
- virtual const char* GetTargetInstName(int opcode);
- virtual std::string BuildInsnString(const char* fmt, LIR* lir, unsigned char* base_addr);
- virtual uint64_t GetPCUseDefEncoding();
- virtual uint64_t GetTargetInstFlags(int opcode);
- virtual int GetInsnSize(LIR* lir);
- virtual bool IsUnconditionalBranch(LIR* lir);
+ AssemblerStatus AssembleInstructions(uintptr_t start_addr);
+ void DumpResourceMask(LIR* lir, uint64_t mask, const char* prefix);
+ void SetupTargetResourceMasks(LIR* lir);
+ const char* GetTargetInstFmt(int opcode);
+ const char* GetTargetInstName(int opcode);
+ std::string BuildInsnString(const char* fmt, LIR* lir, unsigned char* base_addr);
+ uint64_t GetPCUseDefEncoding();
+ uint64_t GetTargetInstFlags(int opcode);
+ int GetInsnSize(LIR* lir);
+ bool IsUnconditionalBranch(LIR* lir);
// Required for target - Dalvik-level generators.
- virtual void GenArithImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
+ void GenArithImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
RegLocation rl_src1, RegLocation rl_src2);
- virtual void GenArrayObjPut(int opt_flags, RegLocation rl_array, RegLocation rl_index,
+ void GenArrayObjPut(int opt_flags, RegLocation rl_array, RegLocation rl_index,
RegLocation rl_src, int scale);
- virtual void GenArrayGet(int opt_flags, OpSize size, RegLocation rl_array,
+ void GenArrayGet(int opt_flags, OpSize size, RegLocation rl_array,
RegLocation rl_index, RegLocation rl_dest, int scale);
- virtual void GenArrayPut(int opt_flags, OpSize size, RegLocation rl_array,
+ void GenArrayPut(int opt_flags, OpSize size, RegLocation rl_array,
RegLocation rl_index, RegLocation rl_src, int scale);
- virtual void GenShiftImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
+ void GenShiftImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
RegLocation rl_src1, RegLocation rl_shift);
- virtual void GenMulLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
- virtual void GenAddLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
- virtual void GenAndLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
- virtual void GenArithOpDouble(Instruction::Code opcode, RegLocation rl_dest,
+ void GenMulLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+ void GenAddLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+ void GenAndLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+ void GenArithOpDouble(Instruction::Code opcode, RegLocation rl_dest,
RegLocation rl_src1, RegLocation rl_src2);
- virtual void GenArithOpFloat(Instruction::Code opcode, RegLocation rl_dest,
+ void GenArithOpFloat(Instruction::Code opcode, RegLocation rl_dest,
RegLocation rl_src1, RegLocation rl_src2);
- virtual void GenCmpFP(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
+ void GenCmpFP(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
RegLocation rl_src2);
- virtual void GenConversion(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src);
- virtual bool GenInlinedCas32(CallInfo* info, bool need_write_barrier);
- virtual bool GenInlinedMinMaxInt(CallInfo* info, bool is_min);
- virtual bool GenInlinedSqrt(CallInfo* info);
- virtual void GenNegLong(RegLocation rl_dest, RegLocation rl_src);
- virtual void GenOrLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
- virtual void GenSubLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
- virtual void GenXorLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
- virtual LIR* GenRegMemCheck(ConditionCode c_code, int reg1, int base, int offset,
+ void GenConversion(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src);
+ bool GenInlinedCas32(CallInfo* info, bool need_write_barrier);
+ bool GenInlinedMinMaxInt(CallInfo* info, bool is_min);
+ bool GenInlinedSqrt(CallInfo* info);
+ void GenNegLong(RegLocation rl_dest, RegLocation rl_src);
+ void GenOrLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+ void GenSubLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+ void GenXorLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+ LIR* GenRegMemCheck(ConditionCode c_code, int reg1, int base, int offset,
ThrowKind kind);
- virtual RegLocation GenDivRem(RegLocation rl_dest, int reg_lo, int reg_hi, bool is_div);
- virtual RegLocation GenDivRemLit(RegLocation rl_dest, int reg_lo, int lit, bool is_div);
- virtual void GenCmpLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
- virtual void GenDivZeroCheck(int reg_lo, int reg_hi);
- virtual void GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method);
- virtual void GenExitSequence();
- virtual void GenFillArrayData(uint32_t table_offset, RegLocation rl_src);
- virtual void GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias, bool is_double);
- virtual void GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir);
- virtual void GenSelect(BasicBlock* bb, MIR* mir);
- virtual void GenMemBarrier(MemBarrierKind barrier_kind);
- virtual void GenMonitorEnter(int opt_flags, RegLocation rl_src);
- virtual void GenMonitorExit(int opt_flags, RegLocation rl_src);
- virtual void GenMoveException(RegLocation rl_dest);
- virtual void GenMultiplyByTwoBitMultiplier(RegLocation rl_src, RegLocation rl_result, int lit,
+ RegLocation GenDivRem(RegLocation rl_dest, int reg_lo, int reg_hi, bool is_div);
+ RegLocation GenDivRemLit(RegLocation rl_dest, int reg_lo, int lit, bool is_div);
+ void GenCmpLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+ void GenDivZeroCheck(int reg_lo, int reg_hi);
+ void GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method);
+ void GenExitSequence();
+ void GenFillArrayData(uint32_t table_offset, RegLocation rl_src);
+ void GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias, bool is_double);
+ void GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir);
+ void GenSelect(BasicBlock* bb, MIR* mir);
+ void GenMemBarrier(MemBarrierKind barrier_kind);
+ void GenMonitorEnter(int opt_flags, RegLocation rl_src);
+ void GenMonitorExit(int opt_flags, RegLocation rl_src);
+ void GenMoveException(RegLocation rl_dest);
+ void GenMultiplyByTwoBitMultiplier(RegLocation rl_src, RegLocation rl_result, int lit,
int first_bit, int second_bit);
- virtual void GenNegDouble(RegLocation rl_dest, RegLocation rl_src);
- virtual void GenNegFloat(RegLocation rl_dest, RegLocation rl_src);
- virtual void GenPackedSwitch(MIR* mir, uint32_t table_offset, RegLocation rl_src);
- virtual void GenSparseSwitch(MIR* mir, uint32_t table_offset, RegLocation rl_src);
- virtual void GenSpecialCase(BasicBlock* bb, MIR* mir, SpecialCaseHandler special_case);
+ void GenNegDouble(RegLocation rl_dest, RegLocation rl_src);
+ void GenNegFloat(RegLocation rl_dest, RegLocation rl_src);
+ void GenPackedSwitch(MIR* mir, uint32_t table_offset, RegLocation rl_src);
+ void GenSparseSwitch(MIR* mir, uint32_t table_offset, RegLocation rl_src);
+ void GenSpecialCase(BasicBlock* bb, MIR* mir, SpecialCaseHandler special_case);
// Required for target - single operation generators.
- virtual LIR* OpUnconditionalBranch(LIR* target);
- virtual LIR* OpCmpBranch(ConditionCode cond, int src1, int src2, LIR* target);
- virtual LIR* OpCmpImmBranch(ConditionCode cond, int reg, int check_value, LIR* target);
- virtual LIR* OpCondBranch(ConditionCode cc, LIR* target);
- virtual LIR* OpDecAndBranch(ConditionCode c_code, int reg, LIR* target);
- virtual LIR* OpFpRegCopy(int r_dest, int r_src);
- virtual LIR* OpIT(ConditionCode cond, const char* guide);
- virtual LIR* OpMem(OpKind op, int rBase, int disp);
- virtual LIR* OpPcRelLoad(int reg, LIR* target);
- virtual LIR* OpReg(OpKind op, int r_dest_src);
- virtual LIR* OpRegCopy(int r_dest, int r_src);
- virtual LIR* OpRegCopyNoInsert(int r_dest, int r_src);
- virtual LIR* OpRegImm(OpKind op, int r_dest_src1, int value);
- virtual LIR* OpRegMem(OpKind op, int r_dest, int rBase, int offset);
- virtual LIR* OpRegReg(OpKind op, int r_dest_src1, int r_src2);
- virtual LIR* OpRegRegImm(OpKind op, int r_dest, int r_src1, int value);
- virtual LIR* OpRegRegReg(OpKind op, int r_dest, int r_src1, int r_src2);
- virtual LIR* OpTestSuspend(LIR* target);
- virtual LIR* OpThreadMem(OpKind op, int thread_offset);
- virtual LIR* OpVldm(int rBase, int count);
- virtual LIR* OpVstm(int rBase, int count);
- virtual void OpLea(int rBase, int reg1, int reg2, int scale, int offset);
- virtual void OpRegCopyWide(int dest_lo, int dest_hi, int src_lo, int src_hi);
- virtual void OpTlsCmp(int offset, int val);
+ LIR* OpUnconditionalBranch(LIR* target);
+ LIR* OpCmpBranch(ConditionCode cond, int src1, int src2, LIR* target);
+ LIR* OpCmpImmBranch(ConditionCode cond, int reg, int check_value, LIR* target);
+ LIR* OpCondBranch(ConditionCode cc, LIR* target);
+ LIR* OpDecAndBranch(ConditionCode c_code, int reg, LIR* target);
+ LIR* OpFpRegCopy(int r_dest, int r_src);
+ LIR* OpIT(ConditionCode cond, const char* guide);
+ LIR* OpMem(OpKind op, int rBase, int disp);
+ LIR* OpPcRelLoad(int reg, LIR* target);
+ LIR* OpReg(OpKind op, int r_dest_src);
+ LIR* OpRegCopy(int r_dest, int r_src);
+ LIR* OpRegCopyNoInsert(int r_dest, int r_src);
+ LIR* OpRegImm(OpKind op, int r_dest_src1, int value);
+ LIR* OpRegMem(OpKind op, int r_dest, int rBase, int offset);
+ LIR* OpRegReg(OpKind op, int r_dest_src1, int r_src2);
+ LIR* OpRegRegImm(OpKind op, int r_dest, int r_src1, int value);
+ LIR* OpRegRegReg(OpKind op, int r_dest, int r_src1, int r_src2);
+ LIR* OpTestSuspend(LIR* target);
+ LIR* OpThreadMem(OpKind op, int thread_offset);
+ LIR* OpVldm(int rBase, int count);
+ LIR* OpVstm(int rBase, int count);
+ void OpLea(int rBase, int reg1, int reg2, int scale, int offset);
+ void OpRegCopyWide(int dest_lo, int dest_hi, int src_lo, int src_hi);
+ void OpTlsCmp(int offset, int val);
LIR* LoadBaseDispBody(int rBase, int displacement, int r_dest, int r_dest_hi, OpSize size,
int s_reg);
diff --git a/src/compiler/dex/quick/mips/fp_mips.cc b/src/compiler/dex/quick/mips/fp_mips.cc
index 5ddec00e80..f384da1a5b 100644
--- a/src/compiler/dex/quick/mips/fp_mips.cc
+++ b/src/compiler/dex/quick/mips/fp_mips.cc
@@ -16,6 +16,7 @@
#include "codegen_mips.h"
#include "mips_lir.h"
+#include "compiler/dex/quick/mir_to_lir-inl.h"
#include "oat/runtime/oat_support_entrypoints.h"
namespace art {
diff --git a/src/compiler/dex/quick/mips/int_mips.cc b/src/compiler/dex/quick/mips/int_mips.cc
index fbff397bd9..fe9e83f879 100644
--- a/src/compiler/dex/quick/mips/int_mips.cc
+++ b/src/compiler/dex/quick/mips/int_mips.cc
@@ -17,6 +17,7 @@
/* This file contains codegen for the Mips ISA */
#include "codegen_mips.h"
+#include "compiler/dex/quick/mir_to_lir-inl.h"
#include "mips_lir.h"
#include "mirror/array.h"
#include "oat/runtime/oat_support_entrypoints.h"
diff --git a/src/compiler/dex/quick/mips/target_mips.cc b/src/compiler/dex/quick/mips/target_mips.cc
index 46a625e83f..356104c86c 100644
--- a/src/compiler/dex/quick/mips/target_mips.cc
+++ b/src/compiler/dex/quick/mips/target_mips.cc
@@ -16,6 +16,7 @@
#include "codegen_mips.h"
#include "compiler/dex/compiler_internals.h"
+#include "compiler/dex/quick/mir_to_lir-inl.h"
#include "mips_lir.h"
#include <string>
diff --git a/src/compiler/dex/quick/mips/utility_mips.cc b/src/compiler/dex/quick/mips/utility_mips.cc
index 5f9f8c58a7..257b0f6cb2 100644
--- a/src/compiler/dex/quick/mips/utility_mips.cc
+++ b/src/compiler/dex/quick/mips/utility_mips.cc
@@ -15,6 +15,7 @@
*/
#include "codegen_mips.h"
+#include "compiler/dex/quick/mir_to_lir-inl.h"
#include "mips_lir.h"
namespace art {
diff --git a/src/compiler/dex/quick/mir_to_lir-inl.h b/src/compiler/dex/quick/mir_to_lir-inl.h
new file mode 100644
index 0000000000..f7546924c8
--- /dev/null
+++ b/src/compiler/dex/quick/mir_to_lir-inl.h
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_SRC_COMPILER_DEX_QUICK_MIR_TO_LIR_INL_H_
+#define ART_SRC_COMPILER_DEX_QUICK_MIR_TO_LIR_INL_H_
+
+#include "mir_to_lir.h"
+
+#include "compiler/dex/compiler_internals.h"
+
+namespace art {
+
+/* Mark a temp register as dead. Does not affect allocation state. */
+inline void Mir2Lir::ClobberBody(RegisterInfo* p) {
+ if (p->is_temp) {
+ DCHECK(!(p->live && p->dirty)) << "Live & dirty temp in clobber";
+ p->live = false;
+ p->s_reg = INVALID_SREG;
+ p->def_start = NULL;
+ p->def_end = NULL;
+ if (p->pair) {
+ p->pair = false;
+ Clobber(p->partner);
+ }
+ }
+}
+
+inline LIR* Mir2Lir::RawLIR(int dalvik_offset, int opcode, int op0,
+ int op1, int op2, int op3, int op4, LIR* target) {
+ LIR* insn = static_cast<LIR*>(arena_->NewMem(sizeof(LIR), true, ArenaAllocator::kAllocLIR));
+ insn->dalvik_offset = dalvik_offset;
+ insn->opcode = opcode;
+ insn->operands[0] = op0;
+ insn->operands[1] = op1;
+ insn->operands[2] = op2;
+ insn->operands[3] = op3;
+ insn->operands[4] = op4;
+ insn->target = target;
+ SetupResourceMasks(insn);
+ if ((opcode == kPseudoTargetLabel) || (opcode == kPseudoSafepointPC) ||
+ (opcode == kPseudoExportedPC)) {
+ // Always make labels scheduling barriers
+ insn->use_mask = insn->def_mask = ENCODE_ALL;
+ }
+ return insn;
+}
+
+/*
+ * The following are building blocks to construct low-level IRs with 0 - 4
+ * operands.
+ */
+inline LIR* Mir2Lir::NewLIR0(int opcode) {
+ DCHECK(is_pseudo_opcode(opcode) || (GetTargetInstFlags(opcode) & NO_OPERAND))
+ << GetTargetInstName(opcode) << " " << opcode << " "
+ << PrettyMethod(cu_->method_idx, *cu_->dex_file) << " "
+ << current_dalvik_offset_;
+ LIR* insn = RawLIR(current_dalvik_offset_, opcode);
+ AppendLIR(insn);
+ return insn;
+}
+
+inline LIR* Mir2Lir::NewLIR1(int opcode, int dest) {
+ DCHECK(is_pseudo_opcode(opcode) || (GetTargetInstFlags(opcode) & IS_UNARY_OP))
+ << GetTargetInstName(opcode) << " " << opcode << " "
+ << PrettyMethod(cu_->method_idx, *cu_->dex_file) << " "
+ << current_dalvik_offset_;
+ LIR* insn = RawLIR(current_dalvik_offset_, opcode, dest);
+ AppendLIR(insn);
+ return insn;
+}
+
+inline LIR* Mir2Lir::NewLIR2(int opcode, int dest, int src1) {
+ DCHECK(is_pseudo_opcode(opcode) || (GetTargetInstFlags(opcode) & IS_BINARY_OP))
+ << GetTargetInstName(opcode) << " " << opcode << " "
+ << PrettyMethod(cu_->method_idx, *cu_->dex_file) << " "
+ << current_dalvik_offset_;
+ LIR* insn = RawLIR(current_dalvik_offset_, opcode, dest, src1);
+ AppendLIR(insn);
+ return insn;
+}
+
+inline LIR* Mir2Lir::NewLIR3(int opcode, int dest, int src1, int src2) {
+ DCHECK(is_pseudo_opcode(opcode) || (GetTargetInstFlags(opcode) & IS_TERTIARY_OP))
+ << GetTargetInstName(opcode) << " " << opcode << " "
+ << PrettyMethod(cu_->method_idx, *cu_->dex_file) << " "
+ << current_dalvik_offset_;
+ LIR* insn = RawLIR(current_dalvik_offset_, opcode, dest, src1, src2);
+ AppendLIR(insn);
+ return insn;
+}
+
+inline LIR* Mir2Lir::NewLIR4(int opcode, int dest, int src1, int src2, int info) {
+ DCHECK(is_pseudo_opcode(opcode) || (GetTargetInstFlags(opcode) & IS_QUAD_OP))
+ << GetTargetInstName(opcode) << " " << opcode << " "
+ << PrettyMethod(cu_->method_idx, *cu_->dex_file) << " "
+ << current_dalvik_offset_;
+ LIR* insn = RawLIR(current_dalvik_offset_, opcode, dest, src1, src2, info);
+ AppendLIR(insn);
+ return insn;
+}
+
+inline LIR* Mir2Lir::NewLIR5(int opcode, int dest, int src1, int src2, int info1,
+ int info2) {
+ DCHECK(is_pseudo_opcode(opcode) || (GetTargetInstFlags(opcode) & IS_QUIN_OP))
+ << GetTargetInstName(opcode) << " " << opcode << " "
+ << PrettyMethod(cu_->method_idx, *cu_->dex_file) << " "
+ << current_dalvik_offset_;
+ LIR* insn = RawLIR(current_dalvik_offset_, opcode, dest, src1, src2, info1, info2);
+ AppendLIR(insn);
+ return insn;
+}
+
+/*
+ * Mark the corresponding bit(s).
+ */
+inline void Mir2Lir::SetupRegMask(uint64_t* mask, int reg) {
+ *mask |= GetRegMaskCommon(reg);
+}
+
+/*
+ * Set up the proper fields in the resource mask
+ */
+inline void Mir2Lir::SetupResourceMasks(LIR* lir) {
+ int opcode = lir->opcode;
+
+ if (opcode <= 0) {
+ lir->use_mask = lir->def_mask = 0;
+ return;
+ }
+
+ uint64_t flags = GetTargetInstFlags(opcode);
+
+ if (flags & NEEDS_FIXUP) {
+ lir->flags.pcRelFixup = true;
+ }
+
+ /* Get the starting size of the instruction's template */
+ lir->flags.size = GetInsnSize(lir);
+
+ /* Set up the mask for resources that are updated */
+ if (flags & (IS_LOAD | IS_STORE)) {
+ /* Default to heap - will catch specialized classes later */
+ SetMemRefType(lir, flags & IS_LOAD, kHeapRef);
+ }
+
+ /*
+ * Conservatively assume the branch here will call out a function that in
+ * turn will trash everything.
+ */
+ if (flags & IS_BRANCH) {
+ lir->def_mask = lir->use_mask = ENCODE_ALL;
+ return;
+ }
+
+ if (flags & REG_DEF0) {
+ SetupRegMask(&lir->def_mask, lir->operands[0]);
+ }
+
+ if (flags & REG_DEF1) {
+ SetupRegMask(&lir->def_mask, lir->operands[1]);
+ }
+
+
+ if (flags & SETS_CCODES) {
+ lir->def_mask |= ENCODE_CCODE;
+ }
+
+ if (flags & (REG_USE0 | REG_USE1 | REG_USE2 | REG_USE3)) {
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ if (flags & (1 << (kRegUse0 + i))) {
+ SetupRegMask(&lir->use_mask, lir->operands[i]);
+ }
+ }
+ }
+
+ if (flags & USES_CCODES) {
+ lir->use_mask |= ENCODE_CCODE;
+ }
+
+ // Handle target-specific actions
+ SetupTargetResourceMasks(lir);
+}
+
+} // namespace art
+
+#endif // ART_SRC_COMPILER_DEX_QUICK_MIR_TO_LIR_INL_H_
diff --git a/src/compiler/dex/quick/mir_to_lir.cc b/src/compiler/dex/quick/mir_to_lir.cc
index 481078d7d5..754aae42dd 100644
--- a/src/compiler/dex/quick/mir_to_lir.cc
+++ b/src/compiler/dex/quick/mir_to_lir.cc
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-#include "object_utils.h"
-
#include "compiler/dex/compiler_internals.h"
-#include "compiler/dex/dataflow_iterator.h"
+#include "compiler/dex/dataflow_iterator-inl.h"
+#include "mir_to_lir-inl.h"
+#include "object_utils.h"
namespace art {
@@ -184,10 +184,10 @@ void Mir2Lir::CompileDalvikInstruction(MIR* mir, BasicBlock* bb, LIR* label_list
GenMonitorExit(opt_flags, rl_src[0]);
break;
- case Instruction::CHECK_CAST:
- GenCheckCast(vB, rl_src[0]);
+ case Instruction::CHECK_CAST: {
+ GenCheckCast(mir->offset, vB, rl_src[0]);
break;
-
+ }
case Instruction::INSTANCE_OF:
GenInstanceof(vC, rl_dest, rl_src[0]);
break;
diff --git a/src/compiler/dex/quick/mir_to_lir.h b/src/compiler/dex/quick/mir_to_lir.h
index 21a0aacc13..9eb4524d0d 100644
--- a/src/compiler/dex/quick/mir_to_lir.h
+++ b/src/compiler/dex/quick/mir_to_lir.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ART_SRC_COMPILER_DEX_QUICK_CODEGEN_H_
-#define ART_SRC_COMPILER_DEX_QUICK_CODEGEN_H_
+#ifndef ART_SRC_COMPILER_DEX_QUICK_MIR_TO_LIR_H_
+#define ART_SRC_COMPILER_DEX_QUICK_MIR_TO_LIR_H_
#include "invoke_type.h"
#include "compiled_method.h"
@@ -24,6 +24,7 @@
#include "compiler/dex/backend.h"
#include "compiler/dex/growable_array.h"
#include "compiler/dex/arena_allocator.h"
+#include "compiler/driver/compiler_driver.h"
#include "safe_map.h"
namespace art {
@@ -98,7 +99,8 @@ struct RegisterInfo;
class MIRGraph;
class Mir2Lir;
-typedef int (*NextCallInsn)(CompilationUnit*, CallInfo*, int, uint32_t dex_idx,
+typedef int (*NextCallInsn)(CompilationUnit*, CallInfo*, int,
+ const CompilerDriver::MethodReference& target_method,
uint32_t method_idx, uintptr_t direct_code,
uintptr_t direct_method, InvokeType type);
@@ -312,8 +314,10 @@ class Mir2Lir : public Backend {
void DumpRegPool(RegisterInfo* p, int num_regs);
void DumpCoreRegPool();
void DumpFpRegPool();
- void ClobberBody(RegisterInfo* p);
- void Clobber(int reg);
+ /* Mark a temp register as dead. Does not affect allocation state. */
+ void Clobber(int reg) {
+ ClobberBody(GetRegInfo(reg));
+ }
void ClobberSRegBody(RegisterInfo* p, int num_regs, int s_reg);
void ClobberSReg(int s_reg);
int SRegToPMap(int s_reg);
@@ -337,7 +341,6 @@ class Mir2Lir : public Backend {
RegisterInfo* IsPromoted(int reg);
bool IsDirty(int reg);
void LockTemp(int reg);
- void ResetDefBody(RegisterInfo* p);
void ResetDef(int reg);
void NullifyRange(LIR *start, LIR *finish, int s_reg1, int s_reg2);
void MarkDef(RegLocation rl, LIR *start, LIR *finish);
@@ -410,7 +413,8 @@ class Mir2Lir : public Backend {
void GenThrow(RegLocation rl_src);
void GenInstanceof(uint32_t type_idx, RegLocation rl_dest,
RegLocation rl_src);
- void GenCheckCast(uint32_t type_idx, RegLocation rl_src);
+ void GenCheckCast(uint32_t insn_idx, uint32_t type_idx,
+ RegLocation rl_src);
void GenLong3Addr(OpKind first_op, OpKind second_op, RegLocation rl_dest,
RegLocation rl_src1, RegLocation rl_src2);
void GenShiftOpLong(Instruction::Code opcode, RegLocation rl_dest,
@@ -462,11 +466,15 @@ class Mir2Lir : public Backend {
void GenInvoke(CallInfo* info);
void FlushIns(RegLocation* ArgLocs, RegLocation rl_method);
int GenDalvikArgsNoRange(CallInfo* info, int call_state, LIR** pcrLabel,
- NextCallInsn next_call_insn, uint32_t dex_idx, uint32_t method_idx,
+ NextCallInsn next_call_insn,
+ const CompilerDriver::MethodReference& target_method,
+ uint32_t vtable_idx,
uintptr_t direct_code, uintptr_t direct_method, InvokeType type,
bool skip_this);
int GenDalvikArgsRange(CallInfo* info, int call_state, LIR** pcrLabel,
- NextCallInsn next_call_insn, uint32_t dex_idx, uint32_t method_idx,
+ NextCallInsn next_call_insn,
+ const CompilerDriver::MethodReference& target_method,
+ uint32_t vtable_idx,
uintptr_t direct_code, uintptr_t direct_method, InvokeType type,
bool skip_this);
RegLocation InlineTarget(CallInfo* info);
@@ -486,7 +494,9 @@ class Mir2Lir : public Backend {
bool is_volatile, bool is_ordered);
bool GenIntrinsic(CallInfo* info);
int LoadArgRegs(CallInfo* info, int call_state,
- NextCallInsn next_call_insn, uint32_t dex_idx, uint32_t method_idx,
+ NextCallInsn next_call_insn,
+ const CompilerDriver::MethodReference& target_method,
+ uint32_t vtable_idx,
uintptr_t direct_code, uintptr_t direct_method, InvokeType type,
bool skip_this);
@@ -681,11 +691,6 @@ class Mir2Lir : public Backend {
// Temp workaround
void Workaround7250540(RegLocation rl_dest, int value);
- // TODO: add accessors for these.
- LIR* literal_list_; // Constants.
- LIR* method_literal_list_; // Method literals requiring patching.
- LIR* code_literal_list_; // Code literals requiring patching.
-
protected:
Mir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena);
@@ -693,6 +698,28 @@ class Mir2Lir : public Backend {
return cu_;
}
+ private:
+ void GenInstanceofFinal(bool use_declaring_class, uint32_t type_idx, RegLocation rl_dest,
+ RegLocation rl_src);
+ void GenInstanceofCallingHelper(bool needs_access_check, bool type_known_final,
+ bool type_known_abstract, bool use_declaring_class,
+ bool can_assume_type_is_in_dex_cache,
+ uint32_t type_idx, RegLocation rl_dest,
+ RegLocation rl_src);
+
+ void ClobberBody(RegisterInfo* p);
+ void ResetDefBody(RegisterInfo* p) {
+ p->def_start = NULL;
+ p->def_end = NULL;
+ }
+
+ public:
+ // TODO: add accessors for these.
+ LIR* literal_list_; // Constants.
+ LIR* method_literal_list_; // Method literals requiring patching.
+ LIR* code_literal_list_; // Code literals requiring patching.
+
+ protected:
CompilationUnit* const cu_;
MIRGraph* const mir_graph_;
GrowableArray<SwitchTable*> switch_tables_;
@@ -749,4 +776,4 @@ class Mir2Lir : public Backend {
} // namespace art
-#endif // ART_SRC_COMPILER_DEX_QUICK_CODEGEN_H_
+#endif //ART_SRC_COMPILER_DEX_QUICK_MIR_TO_LIR_H_
diff --git a/src/compiler/dex/quick/ralloc_util.cc b/src/compiler/dex/quick/ralloc_util.cc
index 30ed1b7db2..8e0dba3a4f 100644
--- a/src/compiler/dex/quick/ralloc_util.cc
+++ b/src/compiler/dex/quick/ralloc_util.cc
@@ -18,6 +18,7 @@
#include "compiler/dex/compiler_ir.h"
#include "compiler/dex/compiler_internals.h"
+#include "mir_to_lir-inl.h"
namespace art {
@@ -84,28 +85,6 @@ void Mir2Lir::DumpFpRegPool()
DumpRegPool(reg_pool_->FPRegs, reg_pool_->num_fp_regs);
}
-/* Mark a temp register as dead. Does not affect allocation state. */
-void Mir2Lir::ClobberBody(RegisterInfo* p)
-{
- if (p->is_temp) {
- DCHECK(!(p->live && p->dirty)) << "Live & dirty temp in clobber";
- p->live = false;
- p->s_reg = INVALID_SREG;
- p->def_start = NULL;
- p->def_end = NULL;
- if (p->pair) {
- p->pair = false;
- Clobber(p->partner);
- }
- }
-}
-
-/* Mark a temp register as dead. Does not affect allocation state. */
-void Mir2Lir::Clobber(int reg)
-{
- ClobberBody(GetRegInfo(reg));
-}
-
void Mir2Lir::ClobberSRegBody(RegisterInfo* p, int num_regs, int s_reg)
{
int i;
@@ -555,12 +534,6 @@ void Mir2Lir::LockTemp(int reg)
LOG(FATAL) << "Tried to lock a non-existant temp: r" << reg;
}
-void Mir2Lir::ResetDefBody(RegisterInfo* p)
-{
- p->def_start = NULL;
- p->def_end = NULL;
-}
-
void Mir2Lir::ResetDef(int reg)
{
ResetDefBody(GetRegInfo(reg));
diff --git a/src/compiler/dex/quick/x86/assemble_x86.cc b/src/compiler/dex/quick/x86/assemble_x86.cc
index f7c1594908..83dabe6c9a 100644
--- a/src/compiler/dex/quick/x86/assemble_x86.cc
+++ b/src/compiler/dex/quick/x86/assemble_x86.cc
@@ -15,6 +15,7 @@
*/
#include "codegen_x86.h"
+#include "compiler/dex/quick/mir_to_lir-inl.h"
#include "x86_lir.h"
namespace art {
diff --git a/src/compiler/dex/quick/x86/call_x86.cc b/src/compiler/dex/quick/x86/call_x86.cc
index 614a72d6c2..dba0e24fab 100644
--- a/src/compiler/dex/quick/x86/call_x86.cc
+++ b/src/compiler/dex/quick/x86/call_x86.cc
@@ -17,6 +17,7 @@
/* This file contains codegen for the X86 ISA */
#include "codegen_x86.h"
+#include "compiler/dex/quick/mir_to_lir-inl.h"
#include "x86_lir.h"
namespace art {
@@ -212,7 +213,7 @@ void X86Mir2Lir::MarkGCCard(int val_reg, int tgt_addr_reg)
int reg_card_no = AllocTemp();
LIR* branch_over = OpCmpImmBranch(kCondEq, val_reg, 0, NULL);
NewLIR2(kX86Mov32RT, reg_card_base, Thread::CardTableOffset().Int32Value());
- OpRegRegImm(kOpLsr, reg_card_no, tgt_addr_reg, CardTable::kCardShift);
+ OpRegRegImm(kOpLsr, reg_card_no, tgt_addr_reg, gc::accounting::CardTable::kCardShift);
StoreBaseIndexed(reg_card_base, reg_card_no, reg_card_base, 0,
kUnsignedByte);
LIR* target = NewLIR0(kPseudoTargetLabel);
diff --git a/src/compiler/dex/quick/x86/codegen_x86.h b/src/compiler/dex/quick/x86/codegen_x86.h
index 99e5148f9b..9050656071 100644
--- a/src/compiler/dex/quick/x86/codegen_x86.h
+++ b/src/compiler/dex/quick/x86/codegen_x86.h
@@ -28,139 +28,139 @@ class X86Mir2Lir : public Mir2Lir {
X86Mir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena);
// Required for target - codegen helpers.
- virtual bool SmallLiteralDivide(Instruction::Code dalvik_opcode, RegLocation rl_src,
+ bool SmallLiteralDivide(Instruction::Code dalvik_opcode, RegLocation rl_src,
RegLocation rl_dest, int lit);
- virtual int LoadHelper(int offset);
- virtual LIR* LoadBaseDisp(int rBase, int displacement, int r_dest, OpSize size, int s_reg);
- virtual LIR* LoadBaseDispWide(int rBase, int displacement, int r_dest_lo, int r_dest_hi,
+ int LoadHelper(int offset);
+ LIR* LoadBaseDisp(int rBase, int displacement, int r_dest, OpSize size, int s_reg);
+ LIR* LoadBaseDispWide(int rBase, int displacement, int r_dest_lo, int r_dest_hi,
int s_reg);
- virtual LIR* LoadBaseIndexed(int rBase, int r_index, int r_dest, int scale, OpSize size);
- virtual LIR* LoadBaseIndexedDisp(int rBase, int r_index, int scale, int displacement,
+ LIR* LoadBaseIndexed(int rBase, int r_index, int r_dest, int scale, OpSize size);
+ LIR* LoadBaseIndexedDisp(int rBase, int r_index, int scale, int displacement,
int r_dest, int r_dest_hi, OpSize size, int s_reg);
- virtual LIR* LoadConstantNoClobber(int r_dest, int value);
- virtual LIR* LoadConstantWide(int r_dest_lo, int r_dest_hi, int64_t value);
- virtual LIR* StoreBaseDisp(int rBase, int displacement, int r_src, OpSize size);
- virtual LIR* StoreBaseDispWide(int rBase, int displacement, int r_src_lo, int r_src_hi);
- virtual LIR* StoreBaseIndexed(int rBase, int r_index, int r_src, int scale, OpSize size);
- virtual LIR* StoreBaseIndexedDisp(int rBase, int r_index, int scale, int displacement,
+ LIR* LoadConstantNoClobber(int r_dest, int value);
+ LIR* LoadConstantWide(int r_dest_lo, int r_dest_hi, int64_t value);
+ LIR* StoreBaseDisp(int rBase, int displacement, int r_src, OpSize size);
+ LIR* StoreBaseDispWide(int rBase, int displacement, int r_src_lo, int r_src_hi);
+ LIR* StoreBaseIndexed(int rBase, int r_index, int r_src, int scale, OpSize size);
+ LIR* StoreBaseIndexedDisp(int rBase, int r_index, int scale, int displacement,
int r_src, int r_src_hi, OpSize size, int s_reg);
- virtual void MarkGCCard(int val_reg, int tgt_addr_reg);
+ void MarkGCCard(int val_reg, int tgt_addr_reg);
// Required for target - register utilities.
- virtual bool IsFpReg(int reg);
- virtual bool SameRegType(int reg1, int reg2);
- virtual int AllocTypedTemp(bool fp_hint, int reg_class);
- virtual int AllocTypedTempPair(bool fp_hint, int reg_class);
- virtual int S2d(int low_reg, int high_reg);
- virtual int TargetReg(SpecialTargetRegister reg);
- virtual RegisterInfo* GetRegInfo(int reg);
- virtual RegLocation GetReturnAlt();
- virtual RegLocation GetReturnWideAlt();
- virtual RegLocation LocCReturn();
- virtual RegLocation LocCReturnDouble();
- virtual RegLocation LocCReturnFloat();
- virtual RegLocation LocCReturnWide();
- virtual uint32_t FpRegMask();
- virtual uint64_t GetRegMaskCommon(int reg);
- virtual void AdjustSpillMask();
- virtual void ClobberCalleeSave();
- virtual void FlushReg(int reg);
- virtual void FlushRegWide(int reg1, int reg2);
- virtual void FreeCallTemps();
- virtual void FreeRegLocTemps(RegLocation rl_keep, RegLocation rl_free);
- virtual void LockCallTemps();
- virtual void MarkPreservedSingle(int v_reg, int reg);
- virtual void CompilerInitializeRegAlloc();
+ bool IsFpReg(int reg);
+ bool SameRegType(int reg1, int reg2);
+ int AllocTypedTemp(bool fp_hint, int reg_class);
+ int AllocTypedTempPair(bool fp_hint, int reg_class);
+ int S2d(int low_reg, int high_reg);
+ int TargetReg(SpecialTargetRegister reg);
+ RegisterInfo* GetRegInfo(int reg);
+ RegLocation GetReturnAlt();
+ RegLocation GetReturnWideAlt();
+ RegLocation LocCReturn();
+ RegLocation LocCReturnDouble();
+ RegLocation LocCReturnFloat();
+ RegLocation LocCReturnWide();
+ uint32_t FpRegMask();
+ uint64_t GetRegMaskCommon(int reg);
+ void AdjustSpillMask();
+ void ClobberCalleeSave();
+ void FlushReg(int reg);
+ void FlushRegWide(int reg1, int reg2);
+ void FreeCallTemps();
+ void FreeRegLocTemps(RegLocation rl_keep, RegLocation rl_free);
+ void LockCallTemps();
+ void MarkPreservedSingle(int v_reg, int reg);
+ void CompilerInitializeRegAlloc();
// Required for target - miscellaneous.
- virtual AssemblerStatus AssembleInstructions(uintptr_t start_addr);
- virtual void DumpResourceMask(LIR* lir, uint64_t mask, const char* prefix);
- virtual void SetupTargetResourceMasks(LIR* lir);
- virtual const char* GetTargetInstFmt(int opcode);
- virtual const char* GetTargetInstName(int opcode);
- virtual std::string BuildInsnString(const char* fmt, LIR* lir, unsigned char* base_addr);
- virtual uint64_t GetPCUseDefEncoding();
- virtual uint64_t GetTargetInstFlags(int opcode);
- virtual int GetInsnSize(LIR* lir);
- virtual bool IsUnconditionalBranch(LIR* lir);
+ AssemblerStatus AssembleInstructions(uintptr_t start_addr);
+ void DumpResourceMask(LIR* lir, uint64_t mask, const char* prefix);
+ void SetupTargetResourceMasks(LIR* lir);
+ const char* GetTargetInstFmt(int opcode);
+ const char* GetTargetInstName(int opcode);
+ std::string BuildInsnString(const char* fmt, LIR* lir, unsigned char* base_addr);
+ uint64_t GetPCUseDefEncoding();
+ uint64_t GetTargetInstFlags(int opcode);
+ int GetInsnSize(LIR* lir);
+ bool IsUnconditionalBranch(LIR* lir);
// Required for target - Dalvik-level generators.
- virtual void GenArithImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
+ void GenArithImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
RegLocation rl_src1, RegLocation rl_src2);
- virtual void GenArrayObjPut(int opt_flags, RegLocation rl_array,
+ void GenArrayObjPut(int opt_flags, RegLocation rl_array,
RegLocation rl_index, RegLocation rl_src, int scale);
- virtual void GenArrayGet(int opt_flags, OpSize size, RegLocation rl_array,
+ void GenArrayGet(int opt_flags, OpSize size, RegLocation rl_array,
RegLocation rl_index, RegLocation rl_dest, int scale);
- virtual void GenArrayPut(int opt_flags, OpSize size, RegLocation rl_array,
+ void GenArrayPut(int opt_flags, OpSize size, RegLocation rl_array,
RegLocation rl_index, RegLocation rl_src, int scale);
- virtual void GenShiftImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
+ void GenShiftImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
RegLocation rl_src1, RegLocation rl_shift);
- virtual void GenMulLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
- virtual void GenAddLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
- virtual void GenAndLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
- virtual void GenArithOpDouble(Instruction::Code opcode, RegLocation rl_dest,
+ void GenMulLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+ void GenAddLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+ void GenAndLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+ void GenArithOpDouble(Instruction::Code opcode, RegLocation rl_dest,
RegLocation rl_src1, RegLocation rl_src2);
- virtual void GenArithOpFloat(Instruction::Code opcode, RegLocation rl_dest,
+ void GenArithOpFloat(Instruction::Code opcode, RegLocation rl_dest,
RegLocation rl_src1, RegLocation rl_src2);
- virtual void GenCmpFP(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
+ void GenCmpFP(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
RegLocation rl_src2);
- virtual void GenConversion(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src);
- virtual bool GenInlinedCas32(CallInfo* info, bool need_write_barrier);
- virtual bool GenInlinedMinMaxInt(CallInfo* info, bool is_min);
- virtual bool GenInlinedSqrt(CallInfo* info);
- virtual void GenNegLong(RegLocation rl_dest, RegLocation rl_src);
- virtual void GenOrLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
- virtual void GenSubLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
- virtual void GenXorLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
- virtual LIR* GenRegMemCheck(ConditionCode c_code, int reg1, int base, int offset,
+ void GenConversion(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src);
+ bool GenInlinedCas32(CallInfo* info, bool need_write_barrier);
+ bool GenInlinedMinMaxInt(CallInfo* info, bool is_min);
+ bool GenInlinedSqrt(CallInfo* info);
+ void GenNegLong(RegLocation rl_dest, RegLocation rl_src);
+ void GenOrLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+ void GenSubLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+ void GenXorLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+ LIR* GenRegMemCheck(ConditionCode c_code, int reg1, int base, int offset,
ThrowKind kind);
- virtual RegLocation GenDivRem(RegLocation rl_dest, int reg_lo, int reg_hi, bool is_div);
- virtual RegLocation GenDivRemLit(RegLocation rl_dest, int reg_lo, int lit, bool is_div);
- virtual void GenCmpLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
- virtual void GenDivZeroCheck(int reg_lo, int reg_hi);
- virtual void GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method);
- virtual void GenExitSequence();
- virtual void GenFillArrayData(uint32_t table_offset, RegLocation rl_src);
- virtual void GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias, bool is_double);
- virtual void GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir);
- virtual void GenSelect(BasicBlock* bb, MIR* mir);
- virtual void GenMemBarrier(MemBarrierKind barrier_kind);
- virtual void GenMonitorEnter(int opt_flags, RegLocation rl_src);
- virtual void GenMonitorExit(int opt_flags, RegLocation rl_src);
- virtual void GenMoveException(RegLocation rl_dest);
- virtual void GenMultiplyByTwoBitMultiplier(RegLocation rl_src, RegLocation rl_result,
+ RegLocation GenDivRem(RegLocation rl_dest, int reg_lo, int reg_hi, bool is_div);
+ RegLocation GenDivRemLit(RegLocation rl_dest, int reg_lo, int lit, bool is_div);
+ void GenCmpLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+ void GenDivZeroCheck(int reg_lo, int reg_hi);
+ void GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method);
+ void GenExitSequence();
+ void GenFillArrayData(uint32_t table_offset, RegLocation rl_src);
+ void GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias, bool is_double);
+ void GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir);
+ void GenSelect(BasicBlock* bb, MIR* mir);
+ void GenMemBarrier(MemBarrierKind barrier_kind);
+ void GenMonitorEnter(int opt_flags, RegLocation rl_src);
+ void GenMonitorExit(int opt_flags, RegLocation rl_src);
+ void GenMoveException(RegLocation rl_dest);
+ void GenMultiplyByTwoBitMultiplier(RegLocation rl_src, RegLocation rl_result,
int lit, int first_bit, int second_bit);
- virtual void GenNegDouble(RegLocation rl_dest, RegLocation rl_src);
- virtual void GenNegFloat(RegLocation rl_dest, RegLocation rl_src);
- virtual void GenPackedSwitch(MIR* mir, uint32_t table_offset, RegLocation rl_src);
- virtual void GenSparseSwitch(MIR* mir, uint32_t table_offset, RegLocation rl_src);
- virtual void GenSpecialCase(BasicBlock* bb, MIR* mir, SpecialCaseHandler special_case);
+ void GenNegDouble(RegLocation rl_dest, RegLocation rl_src);
+ void GenNegFloat(RegLocation rl_dest, RegLocation rl_src);
+ void GenPackedSwitch(MIR* mir, uint32_t table_offset, RegLocation rl_src);
+ void GenSparseSwitch(MIR* mir, uint32_t table_offset, RegLocation rl_src);
+ void GenSpecialCase(BasicBlock* bb, MIR* mir, SpecialCaseHandler special_case);
// Single operation generators.
- virtual LIR* OpUnconditionalBranch(LIR* target);
- virtual LIR* OpCmpBranch(ConditionCode cond, int src1, int src2, LIR* target);
- virtual LIR* OpCmpImmBranch(ConditionCode cond, int reg, int check_value, LIR* target);
- virtual LIR* OpCondBranch(ConditionCode cc, LIR* target);
- virtual LIR* OpDecAndBranch(ConditionCode c_code, int reg, LIR* target);
- virtual LIR* OpFpRegCopy(int r_dest, int r_src);
- virtual LIR* OpIT(ConditionCode cond, const char* guide);
- virtual LIR* OpMem(OpKind op, int rBase, int disp);
- virtual LIR* OpPcRelLoad(int reg, LIR* target);
- virtual LIR* OpReg(OpKind op, int r_dest_src);
- virtual LIR* OpRegCopy(int r_dest, int r_src);
- virtual LIR* OpRegCopyNoInsert(int r_dest, int r_src);
- virtual LIR* OpRegImm(OpKind op, int r_dest_src1, int value);
- virtual LIR* OpRegMem(OpKind op, int r_dest, int rBase, int offset);
- virtual LIR* OpRegReg(OpKind op, int r_dest_src1, int r_src2);
- virtual LIR* OpRegRegImm(OpKind op, int r_dest, int r_src1, int value);
- virtual LIR* OpRegRegReg(OpKind op, int r_dest, int r_src1, int r_src2);
- virtual LIR* OpTestSuspend(LIR* target);
- virtual LIR* OpThreadMem(OpKind op, int thread_offset);
- virtual LIR* OpVldm(int rBase, int count);
- virtual LIR* OpVstm(int rBase, int count);
- virtual void OpLea(int rBase, int reg1, int reg2, int scale, int offset);
- virtual void OpRegCopyWide(int dest_lo, int dest_hi, int src_lo, int src_hi);
- virtual void OpTlsCmp(int offset, int val);
+ LIR* OpUnconditionalBranch(LIR* target);
+ LIR* OpCmpBranch(ConditionCode cond, int src1, int src2, LIR* target);
+ LIR* OpCmpImmBranch(ConditionCode cond, int reg, int check_value, LIR* target);
+ LIR* OpCondBranch(ConditionCode cc, LIR* target);
+ LIR* OpDecAndBranch(ConditionCode c_code, int reg, LIR* target);
+ LIR* OpFpRegCopy(int r_dest, int r_src);
+ LIR* OpIT(ConditionCode cond, const char* guide);
+ LIR* OpMem(OpKind op, int rBase, int disp);
+ LIR* OpPcRelLoad(int reg, LIR* target);
+ LIR* OpReg(OpKind op, int r_dest_src);
+ LIR* OpRegCopy(int r_dest, int r_src);
+ LIR* OpRegCopyNoInsert(int r_dest, int r_src);
+ LIR* OpRegImm(OpKind op, int r_dest_src1, int value);
+ LIR* OpRegMem(OpKind op, int r_dest, int rBase, int offset);
+ LIR* OpRegReg(OpKind op, int r_dest_src1, int r_src2);
+ LIR* OpRegRegImm(OpKind op, int r_dest, int r_src1, int value);
+ LIR* OpRegRegReg(OpKind op, int r_dest, int r_src1, int r_src2);
+ LIR* OpTestSuspend(LIR* target);
+ LIR* OpThreadMem(OpKind op, int thread_offset);
+ LIR* OpVldm(int rBase, int count);
+ LIR* OpVstm(int rBase, int count);
+ void OpLea(int rBase, int reg1, int reg2, int scale, int offset);
+ void OpRegCopyWide(int dest_lo, int dest_hi, int src_lo, int src_hi);
+ void OpTlsCmp(int offset, int val);
void OpRegThreadMem(OpKind op, int r_dest, int thread_offset);
void SpillCoreRegs();
diff --git a/src/compiler/dex/quick/x86/fp_x86.cc b/src/compiler/dex/quick/x86/fp_x86.cc
index db2cf289d8..3341e28ce5 100644
--- a/src/compiler/dex/quick/x86/fp_x86.cc
+++ b/src/compiler/dex/quick/x86/fp_x86.cc
@@ -15,6 +15,7 @@
*/
#include "codegen_x86.h"
+#include "compiler/dex/quick/mir_to_lir-inl.h"
#include "x86_lir.h"
namespace art {
diff --git a/src/compiler/dex/quick/x86/int_x86.cc b/src/compiler/dex/quick/x86/int_x86.cc
index b2ee949f22..fffb900ec9 100644
--- a/src/compiler/dex/quick/x86/int_x86.cc
+++ b/src/compiler/dex/quick/x86/int_x86.cc
@@ -18,6 +18,7 @@
#include "codegen_x86.h"
#include "mirror/array.h"
+#include "compiler/dex/quick/mir_to_lir-inl.h"
#include "x86_lir.h"
namespace art {
diff --git a/src/compiler/dex/quick/x86/target_x86.cc b/src/compiler/dex/quick/x86/target_x86.cc
index e6a49f8ce3..9110b704b8 100644
--- a/src/compiler/dex/quick/x86/target_x86.cc
+++ b/src/compiler/dex/quick/x86/target_x86.cc
@@ -16,6 +16,7 @@
#include "codegen_x86.h"
#include "compiler/dex/compiler_internals.h"
+#include "compiler/dex/quick/mir_to_lir-inl.h"
#include "x86_lir.h"
#include <string>
diff --git a/src/compiler/dex/quick/x86/utility_x86.cc b/src/compiler/dex/quick/x86/utility_x86.cc
index 45c0e9cb41..82466d496b 100644
--- a/src/compiler/dex/quick/x86/utility_x86.cc
+++ b/src/compiler/dex/quick/x86/utility_x86.cc
@@ -15,6 +15,7 @@
*/
#include "codegen_x86.h"
+#include "compiler/dex/quick/mir_to_lir-inl.h"
#include "x86_lir.h"
namespace art {
diff --git a/src/compiler/dex/ssa_transformation.cc b/src/compiler/dex/ssa_transformation.cc
index a90d705c6f..41820720d8 100644
--- a/src/compiler/dex/ssa_transformation.cc
+++ b/src/compiler/dex/ssa_transformation.cc
@@ -15,7 +15,7 @@
*/
#include "compiler_internals.h"
-#include "dataflow_iterator.h"
+#include "dataflow_iterator-inl.h"
#define NOTVISITED (-1)
diff --git a/src/compiler/dex/vreg_analysis.cc b/src/compiler/dex/vreg_analysis.cc
index d4223f1ab1..b941140b00 100644
--- a/src/compiler/dex/vreg_analysis.cc
+++ b/src/compiler/dex/vreg_analysis.cc
@@ -15,7 +15,7 @@
*/
#include "compiler_internals.h"
-#include "dataflow_iterator.h"
+#include "compiler/dex/dataflow_iterator-inl.h"
namespace art {
@@ -292,18 +292,10 @@ bool MIRGraph::InferTypeAndSize(BasicBlock* bb)
is_high |= is_phi && rl_temp.wide && rl_temp.high_word;
}
/*
- * TODO: cleaner fix
- * We don't normally expect to see a Dalvik register
- * definition used both as a floating point and core
- * value. However, the instruction rewriting that occurs
- * during verification can eliminate some type information,
- * leaving us confused. The real fix here is either to
- * add explicit type information to Dalvik byte codes,
- * or to recognize THROW_VERIFICATION_ERROR as
- * an unconditional branch and support dead code elimination.
- * As a workaround we can detect this situation and
- * disable register promotion (which is the only thing that
- * relies on distinctions between core and fp usages.
+ * We don't normally expect to see a Dalvik register definition used both as a
+ * floating point and core value, though technically it could happen with constants.
+ * Until we have proper typing, detect this situation and disable register promotion
+ * (which relies on the distinction between core a fp usages).
*/
if ((defined_fp && (defined_core | defined_ref)) &&
((cu_->disable_opt & (1 << kPromoteRegs)) == 0)) {
diff --git a/src/compiler/driver/compiler_driver.cc b/src/compiler/driver/compiler_driver.cc
index 698517277f..24299ea9bc 100644
--- a/src/compiler/driver/compiler_driver.cc
+++ b/src/compiler/driver/compiler_driver.cc
@@ -24,17 +24,19 @@
#include "base/stl_util.h"
#include "base/timing_logger.h"
#include "class_linker.h"
+#include "compiler/stubs/stubs.h"
#include "dex_compilation_unit.h"
#include "dex_file-inl.h"
#include "jni_internal.h"
#include "oat_file.h"
#include "object_utils.h"
#include "runtime.h"
-#include "gc/card_table-inl.h"
-#include "gc/space.h"
+#include "gc/accounting/card_table-inl.h"
+#include "gc/accounting/heap_bitmap.h"
+#include "gc/space/space.h"
#include "mirror/class_loader.h"
#include "mirror/class-inl.h"
-#include "mirror/dex_cache.h"
+#include "mirror/dex_cache-inl.h"
#include "mirror/field-inl.h"
#include "mirror/abstract_method-inl.h"
#include "mirror/object-inl.h"
@@ -72,7 +74,8 @@ class AOTCompilationStats {
resolved_types_(0), unresolved_types_(0),
resolved_instance_fields_(0), unresolved_instance_fields_(0),
resolved_local_static_fields_(0), resolved_static_fields_(0), unresolved_static_fields_(0),
- type_based_devirtualization_(0) {
+ type_based_devirtualization_(0),
+ safe_casts_(0), not_safe_casts_(0) {
for (size_t i = 0; i <= kMaxInvokeType; i++) {
resolved_methods_[i] = 0;
unresolved_methods_[i] = 0;
@@ -91,8 +94,14 @@ class AOTCompilationStats {
"static fields resolved");
DumpStat(resolved_local_static_fields_, resolved_static_fields_ + unresolved_static_fields_,
"static fields local to a class");
- DumpStat(type_based_devirtualization_,virtual_made_direct_[kInterface] + virtual_made_direct_[kVirtual]
- - type_based_devirtualization_, "sharpened calls based on type information");
+ DumpStat(safe_casts_, not_safe_casts_, "check-casts removed based on type information");
+ // Note, the code below subtracts the stat value so that when added to the stat value we have
+ // 100% of samples. TODO: clean this up.
+ DumpStat(type_based_devirtualization_,
+ resolved_methods_[kVirtual] + unresolved_methods_[kVirtual] +
+ resolved_methods_[kInterface] + unresolved_methods_[kInterface] -
+ type_based_devirtualization_,
+ "virtual/interface calls made direct based on type information");
for (size_t i = 0; i <= kMaxInvokeType; i++) {
std::ostringstream oss;
@@ -184,40 +193,61 @@ class AOTCompilationStats {
unresolved_static_fields_++;
}
+ // Indicate that type information from the verifier led to devirtualization.
void PreciseTypeDevirtualization() {
STATS_LOCK();
type_based_devirtualization_++;
}
+
+ // Indicate that a method of the given type was resolved at compile time.
void ResolvedMethod(InvokeType type) {
DCHECK_LE(type, kMaxInvokeType);
STATS_LOCK();
resolved_methods_[type]++;
}
+ // Indicate that a method of the given type was unresolved at compile time as it was in an
+ // unknown dex file.
void UnresolvedMethod(InvokeType type) {
DCHECK_LE(type, kMaxInvokeType);
STATS_LOCK();
unresolved_methods_[type]++;
}
+ // Indicate that a type of virtual method dispatch has been converted into a direct method
+ // dispatch.
void VirtualMadeDirect(InvokeType type) {
- DCHECK_LE(type, kMaxInvokeType);
+ DCHECK(type == kVirtual || type == kInterface || type == kSuper);
STATS_LOCK();
virtual_made_direct_[type]++;
}
+ // Indicate that a method of the given type was able to call directly into boot.
void DirectCallsToBoot(InvokeType type) {
DCHECK_LE(type, kMaxInvokeType);
STATS_LOCK();
direct_calls_to_boot_[type]++;
}
+ // Indicate that a method of the given type was able to be resolved directly from boot.
void DirectMethodsToBoot(InvokeType type) {
DCHECK_LE(type, kMaxInvokeType);
STATS_LOCK();
direct_methods_to_boot_[type]++;
}
+ // A check-cast could be eliminated due to verifier type analysis.
+ void SafeCast() {
+ STATS_LOCK();
+ safe_casts_++;
+ }
+
+ // A check-cast couldn't be eliminated due to verifier type analysis.
+ void NotASafeCast() {
+ STATS_LOCK();
+ not_safe_casts_++;
+ }
+
private:
Mutex stats_lock_;
@@ -245,6 +275,9 @@ class AOTCompilationStats {
size_t direct_calls_to_boot_[kMaxInvokeType + 1];
size_t direct_methods_to_boot_[kMaxInvokeType + 1];
+ size_t safe_casts_;
+ size_t not_safe_casts_;
+
DISALLOW_COPY_AND_ASSIGN(AOTCompilationStats);
};
@@ -292,8 +325,8 @@ static Fn FindFunction(const std::string& compiler_so_name, void* library, const
}
CompilerDriver::CompilerDriver(CompilerBackend compiler_backend, InstructionSet instruction_set,
- bool image, size_t thread_count, bool support_debugging,
- const std::set<std::string>* image_classes,
+ bool image, DescriptorSet* image_classes,
+ size_t thread_count, bool support_debugging,
bool dump_stats, bool dump_timings)
: compiler_backend_(compiler_backend),
instruction_set_(instruction_set),
@@ -301,18 +334,20 @@ CompilerDriver::CompilerDriver(CompilerBackend compiler_backend, InstructionSet
compiled_classes_lock_("compiled classes lock"),
compiled_methods_lock_("compiled method lock"),
image_(image),
+ image_classes_(image_classes),
thread_count_(thread_count),
support_debugging_(support_debugging),
start_ns_(0),
stats_(new AOTCompilationStats),
dump_stats_(dump_stats),
dump_timings_(dump_timings),
- image_classes_(image_classes),
compiler_library_(NULL),
compiler_(NULL),
compiler_context_(NULL),
jni_compiler_(NULL),
- compiler_get_method_code_addr_(NULL)
+ compiler_enable_auto_elf_loading_(NULL),
+ compiler_get_method_code_addr_(NULL),
+ support_boot_image_fixup_(true)
{
std::string compiler_so_name(MakeCompilerSoName(compiler_backend_));
compiler_library_ = dlopen(compiler_so_name.c_str(), RTLD_LAZY);
@@ -337,6 +372,13 @@ CompilerDriver::CompilerDriver(CompilerBackend compiler_backend, InstructionSet
compiler_ = FindFunction<CompilerFn>(compiler_so_name, compiler_library_, "ArtQuickCompileMethod");
}
+ dex_to_dex_compiler_ = FindFunction<CompilerFn>(compiler_so_name, compiler_library_, "ArtCompileDEX");
+
+ sea_ir_compiler_ = NULL;
+ if (Runtime::Current()->IsSeaIRMode()) {
+ sea_ir_compiler_ = FindFunction<CompilerFn>(compiler_so_name, compiler_library_, "SeaIrCompileMethod");
+ }
+
init_compiler_context(*this);
if (compiler_backend_ == kPortable) {
@@ -347,7 +389,7 @@ CompilerDriver::CompilerDriver(CompilerBackend compiler_backend, InstructionSet
CHECK(!Runtime::Current()->IsStarted());
if (!image_) {
- CHECK(image_classes_ == NULL);
+ CHECK(image_classes_.get() == NULL);
}
}
@@ -416,6 +458,66 @@ CompilerTls* CompilerDriver::GetTls() {
return res;
}
+const std::vector<uint8_t>* CompilerDriver::CreatePortableResolutionTrampoline() const {
+ switch (instruction_set_) {
+ case kArm:
+ case kThumb2:
+ return arm::CreatePortableResolutionTrampoline();
+ case kMips:
+ return mips::CreatePortableResolutionTrampoline();
+ case kX86:
+ return x86::CreatePortableResolutionTrampoline();
+ default:
+ LOG(FATAL) << "Unknown InstructionSet: " << instruction_set_;
+ return NULL;
+ }
+}
+
+const std::vector<uint8_t>* CompilerDriver::CreateQuickResolutionTrampoline() const {
+ switch (instruction_set_) {
+ case kArm:
+ case kThumb2:
+ return arm::CreateQuickResolutionTrampoline();
+ case kMips:
+ return mips::CreateQuickResolutionTrampoline();
+ case kX86:
+ return x86::CreateQuickResolutionTrampoline();
+ default:
+ LOG(FATAL) << "Unknown InstructionSet: " << instruction_set_;
+ return NULL;
+ }
+}
+
+const std::vector<uint8_t>* CompilerDriver::CreateInterpreterToInterpreterEntry() const {
+ switch (instruction_set_) {
+ case kArm:
+ case kThumb2:
+ return arm::CreateInterpreterToInterpreterEntry();
+ case kMips:
+ return mips::CreateInterpreterToInterpreterEntry();
+ case kX86:
+ return x86::CreateInterpreterToInterpreterEntry();
+ default:
+ LOG(FATAL) << "Unknown InstructionSet: " << instruction_set_;
+ return NULL;
+ }
+}
+
+const std::vector<uint8_t>* CompilerDriver::CreateInterpreterToQuickEntry() const {
+ switch (instruction_set_) {
+ case kArm:
+ case kThumb2:
+ return arm::CreateInterpreterToQuickEntry();
+ case kMips:
+ return mips::CreateInterpreterToQuickEntry();
+ case kX86:
+ return x86::CreateInterpreterToQuickEntry();
+ default:
+ LOG(FATAL) << "Unknown InstructionSet: " << instruction_set_;
+ return NULL;
+ }
+}
+
void CompilerDriver::CompileAll(jobject class_loader,
const std::vector<const DexFile*>& dex_files) {
DCHECK(!Runtime::Current()->IsStarted());
@@ -436,10 +538,33 @@ void CompilerDriver::CompileAll(jobject class_loader,
}
}
+static bool IsDexToDexCompilationAllowed(mirror::ClassLoader* class_loader,
+ const DexFile& dex_file,
+ const DexFile::ClassDef& class_def)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ // Do not allow DEX-to-DEX compilation of image classes. This is to prevent the
+ // verifier from passing on "quick" instruction at compilation time. It must
+ // only pass on quick instructions at runtime.
+ if (class_loader == NULL) {
+ return false;
+ }
+ const char* descriptor = dex_file.GetClassDescriptor(class_def);
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ mirror::Class* klass = class_linker->FindClass(descriptor, class_loader);
+ if (klass == NULL) {
+ Thread* self = Thread::Current();
+ CHECK(self->IsExceptionPending());
+ self->ClearException();
+ return false;
+ }
+ // DEX-to-DEX compilation is only allowed on preverified classes.
+ return klass->IsVerified();
+}
+
void CompilerDriver::CompileOne(const mirror::AbstractMethod* method) {
DCHECK(!Runtime::Current()->IsStarted());
Thread* self = Thread::Current();
- jobject class_loader;
+ jobject jclass_loader;
const DexFile* dex_file;
uint32_t class_def_idx;
{
@@ -447,7 +572,7 @@ void CompilerDriver::CompileOne(const mirror::AbstractMethod* method) {
ScopedLocalRef<jobject>
local_class_loader(soa.Env(),
soa.AddLocalReference<jobject>(method->GetDeclaringClass()->GetClassLoader()));
- class_loader = soa.Env()->NewGlobalRef(local_class_loader.get());
+ jclass_loader = soa.Env()->NewGlobalRef(local_class_loader.get());
// Find the dex_file
MethodHelper mh(method);
dex_file = &mh.GetDexFile();
@@ -460,14 +585,22 @@ void CompilerDriver::CompileOne(const mirror::AbstractMethod* method) {
UniquePtr<ThreadPool> thread_pool(new ThreadPool(1U));
TimingLogger timings("CompileOne", false);
- PreCompile(class_loader, dex_files, *thread_pool.get(), timings);
+ PreCompile(jclass_loader, dex_files, *thread_pool.get(), timings);
uint32_t method_idx = method->GetDexMethodIndex();
const DexFile::CodeItem* code_item = dex_file->GetCodeItem(method->GetCodeItemOffset());
+ // Can we run DEX-to-DEX compiler on this class ?
+ bool allow_dex_compilation;
+ {
+ ScopedObjectAccess soa(Thread::Current());
+ const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_idx);
+ mirror::ClassLoader* class_loader = soa.Decode<mirror::ClassLoader*>(jclass_loader);
+ allow_dex_compilation = IsDexToDexCompilationAllowed(class_loader, *dex_file, class_def);
+ }
CompileMethod(code_item, method->GetAccessFlags(), method->GetInvokeType(),
- class_def_idx, method_idx, class_loader, *dex_file);
+ class_def_idx, method_idx, jclass_loader, *dex_file, allow_dex_compilation);
- self->GetJniEnv()->DeleteGlobalRef(class_loader);
+ self->GetJniEnv()->DeleteGlobalRef(jclass_loader);
self->TransitionFromSuspendedToRunnable();
}
@@ -483,20 +616,199 @@ void CompilerDriver::Resolve(jobject class_loader, const std::vector<const DexFi
void CompilerDriver::PreCompile(jobject class_loader, const std::vector<const DexFile*>& dex_files,
ThreadPool& thread_pool, TimingLogger& timings) {
+ LoadImageClasses(timings);
+
Resolve(class_loader, dex_files, thread_pool, timings);
Verify(class_loader, dex_files, thread_pool, timings);
InitializeClasses(class_loader, dex_files, thread_pool, timings);
+
+ UpdateImageClasses(timings);
}
-bool CompilerDriver::IsImageClass(const std::string& descriptor) const {
- if (image_classes_ == NULL) {
- return false;
+bool CompilerDriver::IsImageClass(const char* descriptor) const {
+ DCHECK(descriptor != NULL);
+ if (image_classes_.get() == NULL) {
+ return true;
}
return image_classes_->find(descriptor) != image_classes_->end();
}
+static void ResolveExceptionsForMethod(MethodHelper* mh,
+ std::set<std::pair<uint16_t, const DexFile*> >& exceptions_to_resolve)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ const DexFile::CodeItem* code_item = mh->GetCodeItem();
+ if (code_item == NULL) {
+ return; // native or abstract method
+ }
+ if (code_item->tries_size_ == 0) {
+ return; // nothing to process
+ }
+ const byte* encoded_catch_handler_list = DexFile::GetCatchHandlerData(*code_item, 0);
+ size_t num_encoded_catch_handlers = DecodeUnsignedLeb128(&encoded_catch_handler_list);
+ for (size_t i = 0; i < num_encoded_catch_handlers; i++) {
+ int32_t encoded_catch_handler_size = DecodeSignedLeb128(&encoded_catch_handler_list);
+ bool has_catch_all = false;
+ if (encoded_catch_handler_size <= 0) {
+ encoded_catch_handler_size = -encoded_catch_handler_size;
+ has_catch_all = true;
+ }
+ for (int32_t j = 0; j < encoded_catch_handler_size; j++) {
+ uint16_t encoded_catch_handler_handlers_type_idx =
+ DecodeUnsignedLeb128(&encoded_catch_handler_list);
+ // Add to set of types to resolve if not already in the dex cache resolved types
+ if (!mh->IsResolvedTypeIdx(encoded_catch_handler_handlers_type_idx)) {
+ exceptions_to_resolve.insert(
+ std::pair<uint16_t, const DexFile*>(encoded_catch_handler_handlers_type_idx,
+ &mh->GetDexFile()));
+ }
+ // ignore address associated with catch handler
+ DecodeUnsignedLeb128(&encoded_catch_handler_list);
+ }
+ if (has_catch_all) {
+ // ignore catch all address
+ DecodeUnsignedLeb128(&encoded_catch_handler_list);
+ }
+ }
+}
+
+static bool ResolveCatchBlockExceptionsClassVisitor(mirror::Class* c, void* arg)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ std::set<std::pair<uint16_t, const DexFile*> >* exceptions_to_resolve =
+ reinterpret_cast<std::set<std::pair<uint16_t, const DexFile*> >*>(arg);
+ MethodHelper mh;
+ for (size_t i = 0; i < c->NumVirtualMethods(); ++i) {
+ mirror::AbstractMethod* m = c->GetVirtualMethod(i);
+ mh.ChangeMethod(m);
+ ResolveExceptionsForMethod(&mh, *exceptions_to_resolve);
+ }
+ for (size_t i = 0; i < c->NumDirectMethods(); ++i) {
+ mirror::AbstractMethod* m = c->GetDirectMethod(i);
+ mh.ChangeMethod(m);
+ ResolveExceptionsForMethod(&mh, *exceptions_to_resolve);
+ }
+ return true;
+}
+
+static bool RecordImageClassesVisitor(mirror::Class* klass, void* arg)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ CompilerDriver::DescriptorSet* image_classes =
+ reinterpret_cast<CompilerDriver::DescriptorSet*>(arg);
+ image_classes->insert(ClassHelper(klass).GetDescriptor());
+ return true;
+}
+
+// Make a list of descriptors for classes to include in the image
+void CompilerDriver::LoadImageClasses(TimingLogger& timings)
+ LOCKS_EXCLUDED(Locks::mutator_lock_) {
+ if (image_classes_.get() == NULL) {
+ return;
+ }
+
+ // Make a first class to load all classes explicitly listed in the file
+ Thread* self = Thread::Current();
+ ScopedObjectAccess soa(self);
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ typedef DescriptorSet::iterator It; // TODO: C++0x auto
+ for (It it = image_classes_->begin(), end = image_classes_->end(); it != end;) {
+ std::string descriptor(*it);
+ SirtRef<mirror::Class> klass(self, class_linker->FindSystemClass(descriptor.c_str()));
+ if (klass.get() == NULL) {
+ image_classes_->erase(it++);
+ LOG(WARNING) << "Failed to find class " << descriptor;
+ Thread::Current()->ClearException();
+ } else {
+ ++it;
+ }
+ }
+
+ // Resolve exception classes referenced by the loaded classes. The catch logic assumes
+ // exceptions are resolved by the verifier when there is a catch block in an interested method.
+ // Do this here so that exception classes appear to have been specified image classes.
+ std::set<std::pair<uint16_t, const DexFile*> > unresolved_exception_types;
+ SirtRef<mirror::Class> java_lang_Throwable(self,
+ class_linker->FindSystemClass("Ljava/lang/Throwable;"));
+ do {
+ unresolved_exception_types.clear();
+ class_linker->VisitClasses(ResolveCatchBlockExceptionsClassVisitor,
+ &unresolved_exception_types);
+ typedef std::set<std::pair<uint16_t, const DexFile*> >::const_iterator It; // TODO: C++0x auto
+ for (It it = unresolved_exception_types.begin(),
+ end = unresolved_exception_types.end();
+ it != end; ++it) {
+ uint16_t exception_type_idx = it->first;
+ const DexFile* dex_file = it->second;
+ mirror::DexCache* dex_cache = class_linker->FindDexCache(*dex_file);
+ mirror:: ClassLoader* class_loader = NULL;
+ SirtRef<mirror::Class> klass(self, class_linker->ResolveType(*dex_file, exception_type_idx,
+ dex_cache, class_loader));
+ if (klass.get() == NULL) {
+ const DexFile::TypeId& type_id = dex_file->GetTypeId(exception_type_idx);
+ const char* descriptor = dex_file->GetTypeDescriptor(type_id);
+ LOG(FATAL) << "Failed to resolve class " << descriptor;
+ }
+ DCHECK(java_lang_Throwable->IsAssignableFrom(klass.get()));
+ }
+ // Resolving exceptions may load classes that reference more exceptions, iterate until no
+ // more are found
+ } while (!unresolved_exception_types.empty());
+
+ // We walk the roots looking for classes so that we'll pick up the
+ // above classes plus any classes them depend on such super
+ // classes, interfaces, and the required ClassLinker roots.
+ class_linker->VisitClasses(RecordImageClassesVisitor, image_classes_.get());
+
+ CHECK_NE(image_classes_->size(), 0U);
+ timings.AddSplit("LoadImageClasses");
+}
+
+static void MaybeAddToImageClasses(mirror::Class* klass, CompilerDriver::DescriptorSet* image_classes)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ while (!klass->IsObjectClass()) {
+ ClassHelper kh(klass);
+ const char* descriptor = kh.GetDescriptor();
+ std::pair<CompilerDriver::DescriptorSet::iterator, bool> result =
+ image_classes->insert(descriptor);
+ if (result.second) {
+ LOG(INFO) << "Adding " << descriptor << " to image classes";
+ } else {
+ return;
+ }
+ for (size_t i = 0; i < kh.NumDirectInterfaces(); ++i) {
+ MaybeAddToImageClasses(kh.GetDirectInterface(i), image_classes);
+ }
+ if (klass->IsArrayClass()) {
+ MaybeAddToImageClasses(klass->GetComponentType(), image_classes);
+ }
+ klass = klass->GetSuperClass();
+ }
+}
+
+void CompilerDriver::FindClinitImageClassesCallback(mirror::Object* object, void* arg) {
+ DCHECK(object != NULL);
+ DCHECK(arg != NULL);
+ CompilerDriver* compiler_driver = reinterpret_cast<CompilerDriver*>(arg);
+ MaybeAddToImageClasses(object->GetClass(), compiler_driver->image_classes_.get());
+}
+
+void CompilerDriver::UpdateImageClasses(TimingLogger& timings) {
+ if (image_classes_.get() == NULL) {
+ return;
+ }
+
+ // Update image_classes_ with classes for objects created by <clinit> methods.
+ Thread* self = Thread::Current();
+ const char* old_cause = self->StartAssertNoThreadSuspension("ImageWriter");
+ gc::Heap* heap = Runtime::Current()->GetHeap();
+ // TODO: Image spaces only?
+ WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
+ heap->FlushAllocStack();
+ heap->GetLiveBitmap()->Walk(FindClinitImageClassesCallback, this);
+ self->EndAssertNoThreadSuspension(old_cause);
+ timings.AddSplit("UpdateImageClasses");
+}
+
void CompilerDriver::RecordClassStatus(ClassReference ref, CompiledClass* compiled_class) {
MutexLock mu(Thread::Current(), CompilerDriver::compiled_classes_lock_);
compiled_classes_.Put(ref, compiled_class);
@@ -504,24 +816,19 @@ void CompilerDriver::RecordClassStatus(ClassReference ref, CompiledClass* compil
bool CompilerDriver::CanAssumeTypeIsPresentInDexCache(const DexFile& dex_file,
uint32_t type_idx) {
- ScopedObjectAccess soa(Thread::Current());
- mirror::DexCache* dex_cache = Runtime::Current()->GetClassLinker()->FindDexCache(dex_file);
- if (!IsImage()) {
- stats_->TypeNotInDexCache();
- return false;
- }
- mirror::Class* resolved_class = dex_cache->GetResolvedType(type_idx);
- if (resolved_class == NULL) {
- stats_->TypeNotInDexCache();
- return false;
- }
- bool result = IsImageClass(ClassHelper(resolved_class).GetDescriptor());
- if (result) {
+ if (IsImage() && IsImageClass(dex_file.GetTypeDescriptor(dex_file.GetTypeId(type_idx)))) {
+ if (kIsDebugBuild) {
+ ScopedObjectAccess soa(Thread::Current());
+ mirror::DexCache* dex_cache = Runtime::Current()->GetClassLinker()->FindDexCache(dex_file);
+ mirror::Class* resolved_class = dex_cache->GetResolvedType(type_idx);
+ CHECK(resolved_class != NULL);
+ }
stats_->TypeInDexCache();
+ return true;
} else {
stats_->TypeNotInDexCache();
+ return false;
}
- return result;
}
bool CompilerDriver::CanAssumeStringIsPresentInDexCache(const DexFile& dex_file,
@@ -545,7 +852,18 @@ bool CompilerDriver::CanAssumeStringIsPresentInDexCache(const DexFile& dex_file,
}
bool CompilerDriver::CanAccessTypeWithoutChecks(uint32_t referrer_idx, const DexFile& dex_file,
- uint32_t type_idx) {
+ uint32_t type_idx,
+ bool* type_known_final, bool* type_known_abstract,
+ bool* equals_referrers_class) {
+ if (type_known_final != NULL) {
+ *type_known_final = false;
+ }
+ if (type_known_abstract != NULL) {
+ *type_known_abstract = false;
+ }
+ if (equals_referrers_class != NULL) {
+ *equals_referrers_class = false;
+ }
ScopedObjectAccess soa(Thread::Current());
mirror::DexCache* dex_cache = Runtime::Current()->GetClassLinker()->FindDexCache(dex_file);
// Get type from dex cache assuming it was populated by the verifier
@@ -555,6 +873,9 @@ bool CompilerDriver::CanAccessTypeWithoutChecks(uint32_t referrer_idx, const Dex
return false; // Unknown class needs access checks.
}
const DexFile::MethodId& method_id = dex_file.GetMethodId(referrer_idx);
+ if (equals_referrers_class != NULL) {
+ *equals_referrers_class = (method_id.class_idx_ == type_idx);
+ }
mirror::Class* referrer_class = dex_cache->GetResolvedType(method_id.class_idx_);
if (referrer_class == NULL) {
stats_->TypeNeedsAccessCheck();
@@ -565,6 +886,12 @@ bool CompilerDriver::CanAccessTypeWithoutChecks(uint32_t referrer_idx, const Dex
bool result = referrer_class->CanAccess(resolved_class);
if (result) {
stats_->TypeDoesntNeedAccessCheck();
+ if (type_known_final != NULL) {
+ *type_known_final = resolved_class->IsFinal() && !resolved_class->IsArrayClass();
+ }
+ if (type_known_abstract != NULL) {
+ *type_known_abstract = resolved_class->IsAbstract() && !resolved_class->IsArrayClass();
+ }
} else {
stats_->TypeNeedsAccessCheck();
}
@@ -600,9 +927,14 @@ bool CompilerDriver::CanAccessInstantiableTypeWithoutChecks(uint32_t referrer_id
}
static mirror::Class* ComputeCompilingMethodsClass(ScopedObjectAccess& soa,
+ mirror::DexCache* dex_cache,
const DexCompilationUnit* mUnit)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- mirror::DexCache* dex_cache = mUnit->GetClassLinker()->FindDexCache(*mUnit->GetDexFile());
+ // The passed dex_cache is a hint, sanity check before asking the class linker that will take a
+ // lock.
+ if (dex_cache->GetDexFile() != mUnit->GetDexFile()) {
+ dex_cache = mUnit->GetClassLinker()->FindDexCache(*mUnit->GetDexFile());
+ }
mirror::ClassLoader* class_loader = soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader());
const DexFile::MethodId& referrer_method_id = mUnit->GetDexFile()->GetMethodId(mUnit->GetDexMethodIndex());
return mUnit->GetClassLinker()->ResolveType(*mUnit->GetDexFile(), referrer_method_id.class_idx_,
@@ -639,7 +971,9 @@ bool CompilerDriver::ComputeInstanceFieldInfo(uint32_t field_idx, const DexCompi
// Try to resolve field and ignore if an Incompatible Class Change Error (ie is static).
mirror::Field* resolved_field = ComputeFieldReferencedFromCompilingMethod(soa, mUnit, field_idx);
if (resolved_field != NULL && !resolved_field->IsStatic()) {
- mirror::Class* referrer_class = ComputeCompilingMethodsClass(soa, mUnit);
+ mirror::Class* referrer_class =
+ ComputeCompilingMethodsClass(soa, resolved_field->GetDeclaringClass()->GetDexCache(),
+ mUnit);
if (referrer_class != NULL) {
mirror::Class* fields_class = resolved_field->GetDeclaringClass();
bool access_ok = referrer_class->CanAccess(fields_class) &&
@@ -688,7 +1022,9 @@ bool CompilerDriver::ComputeStaticFieldInfo(uint32_t field_idx, const DexCompila
// Try to resolve field and ignore if an Incompatible Class Change Error (ie isn't static).
mirror::Field* resolved_field = ComputeFieldReferencedFromCompilingMethod(soa, mUnit, field_idx);
if (resolved_field != NULL && resolved_field->IsStatic()) {
- mirror::Class* referrer_class = ComputeCompilingMethodsClass(soa, mUnit);
+ mirror::Class* referrer_class =
+ ComputeCompilingMethodsClass(soa, resolved_field->GetDeclaringClass()->GetDexCache(),
+ mUnit);
if (referrer_class != NULL) {
mirror::Class* fields_class = resolved_field->GetDeclaringClass();
if (fields_class == referrer_class) {
@@ -733,9 +1069,8 @@ bool CompilerDriver::ComputeStaticFieldInfo(uint32_t field_idx, const DexCompila
}
// Search dex file for localized ssb index, may fail if field's class is a parent
// of the class mentioned in the dex file and there is no dex cache entry.
- std::string descriptor(FieldHelper(resolved_field).GetDeclaringClassDescriptor());
const DexFile::StringId* string_id =
- mUnit->GetDexFile()->FindStringId(descriptor);
+ mUnit->GetDexFile()->FindStringId(FieldHelper(resolved_field).GetDeclaringClassDescriptor());
if (string_id != NULL) {
const DexFile::TypeId* type_id =
mUnit->GetDexFile()->FindTypeId(mUnit->GetDexFile()->GetIndexForStringId(*string_id));
@@ -764,7 +1099,8 @@ void CompilerDriver::GetCodeAndMethodForDirectCall(InvokeType type, InvokeType s
mirror::Class* referrer_class,
mirror::AbstractMethod* method,
uintptr_t& direct_code,
- uintptr_t& direct_method) {
+ uintptr_t& direct_method,
+ bool update_stats) {
// For direct and static methods compute possible direct_code and direct_method values, ie
// an address for the Method* being invoked and an address of the code for that Method*.
// For interface calls compute a value for direct_method that is the interface method being
@@ -789,14 +1125,15 @@ void CompilerDriver::GetCodeAndMethodForDirectCall(InvokeType type, InvokeType s
// Ensure we run the clinit trampoline unless we are invoking a static method in the same class.
return;
}
- if (sharp_type != kInterface) { // Interfaces always go via a trampoline.
- stats_->DirectCallsToBoot(type);
+ if (update_stats) {
+ if (sharp_type != kInterface) { // Interfaces always go via a trampoline.
+ stats_->DirectCallsToBoot(type);
+ }
+ stats_->DirectMethodsToBoot(type);
}
- stats_->DirectMethodsToBoot(type);
- bool compiling_boot = Runtime::Current()->GetHeap()->GetSpaces().size() == 1;
+ bool compiling_boot = Runtime::Current()->GetHeap()->GetContinuousSpaces().size() == 1;
if (compiling_boot) {
- const bool kSupportBootImageFixup = true;
- if (kSupportBootImageFixup) {
+ if (support_boot_image_fixup_) {
MethodHelper mh(method);
if (IsImageClass(mh.GetDeclaringClassDescriptor())) {
// We can only branch directly to Methods that are resolved in the DexCache.
@@ -806,33 +1143,33 @@ void CompilerDriver::GetCodeAndMethodForDirectCall(InvokeType type, InvokeType s
}
}
} else {
- if (Runtime::Current()->GetHeap()->FindSpaceFromObject(method)->IsImageSpace()) {
+ if (Runtime::Current()->GetHeap()->FindSpaceFromObject(method, false)->IsImageSpace()) {
direct_method = reinterpret_cast<uintptr_t>(method);
}
direct_code = reinterpret_cast<uintptr_t>(method->GetEntryPointFromCompiledCode());
}
}
-bool CompilerDriver::ComputeInvokeInfo(uint32_t method_idx,const uint32_t dex_pc,
- const DexCompilationUnit* mUnit, InvokeType& type,
- int& vtable_idx, uintptr_t& direct_code,
- uintptr_t& direct_method) {
+bool CompilerDriver::ComputeInvokeInfo(const DexCompilationUnit* mUnit, const uint32_t dex_pc,
+ InvokeType& invoke_type,
+ MethodReference& target_method,
+ int& vtable_idx,
+ uintptr_t& direct_code, uintptr_t& direct_method,
+ bool update_stats) {
ScopedObjectAccess soa(Thread::Current());
-
- const bool kEnableVerifierBasedSharpening = true;
- const CompilerDriver::MethodReference ref_caller(mUnit->GetDexFile(), mUnit->GetDexMethodIndex());
- const CompilerDriver::MethodReference* ref_sharpen = verifier::MethodVerifier::GetDevirtMap(ref_caller, dex_pc);
- bool can_devirtualize = (dex_pc != art::kDexPCNotReady) && (ref_sharpen != NULL);
vtable_idx = -1;
direct_code = 0;
direct_method = 0;
mirror::AbstractMethod* resolved_method =
- ComputeMethodReferencedFromCompilingMethod(soa, mUnit, method_idx, type);
+ ComputeMethodReferencedFromCompilingMethod(soa, mUnit, target_method.dex_method_index,
+ invoke_type);
if (resolved_method != NULL) {
// Don't try to fast-path if we don't understand the caller's class or this appears to be an
// Incompatible Class Change Error.
- mirror::Class* referrer_class = ComputeCompilingMethodsClass(soa, mUnit);
- bool icce = resolved_method->CheckIncompatibleClassChange(type);
+ mirror::Class* referrer_class =
+ ComputeCompilingMethodsClass(soa, resolved_method->GetDeclaringClass()->GetDexCache(),
+ mUnit);
+ bool icce = resolved_method->CheckIncompatibleClassChange(invoke_type);
if (referrer_class != NULL && !icce) {
mirror::Class* methods_class = resolved_method->GetDeclaringClass();
if (!referrer_class->CanAccess(methods_class) ||
@@ -842,74 +1179,168 @@ bool CompilerDriver::ComputeInvokeInfo(uint32_t method_idx,const uint32_t dex_pc
// protected method being made public by implementing an interface that re-declares the
// method public. Resort to the dex file to determine the correct class for the access
// check.
- const DexFile& dex_file = *referrer_class->GetDexCache()->GetDexFile();
- methods_class =
- mUnit->GetClassLinker()->ResolveType(dex_file,
- dex_file.GetMethodId(method_idx).class_idx_,
- referrer_class);
+ uint16_t class_idx =
+ target_method.dex_file->GetMethodId(target_method.dex_method_index).class_idx_;
+ methods_class = mUnit->GetClassLinker()->ResolveType(*target_method.dex_file,
+ class_idx, referrer_class);
}
if (referrer_class->CanAccess(methods_class) &&
referrer_class->CanAccessMember(methods_class, resolved_method->GetAccessFlags())) {
- vtable_idx = resolved_method->GetMethodIndex();
- const bool kEnableSharpening = true;
- // Sharpen a virtual call into a direct call when the target is known.
- bool can_sharpen = type == kVirtual && (resolved_method->IsFinal() ||
- methods_class->IsFinal());
- // Ensure the vtable index will be correct to dispatch in the vtable of the super class.
- can_sharpen = can_sharpen || (type == kSuper && referrer_class != methods_class &&
- referrer_class->IsSubClass(methods_class) &&
- vtable_idx < methods_class->GetVTable()->GetLength() &&
- methods_class->GetVTable()->Get(vtable_idx) == resolved_method);
-
- if (kEnableSharpening && can_sharpen) {
- stats_->ResolvedMethod(type);
+ const bool kEnableFinalBasedSharpening = true;
+ // Sharpen a virtual call into a direct call when the target is known not to have been
+ // overridden (ie is final).
+ bool can_sharpen_virtual_based_on_type =
+ (invoke_type == kVirtual) && (resolved_method->IsFinal() || methods_class->IsFinal());
+ // For invoke-super, ensure the vtable index will be correct to dispatch in the vtable of
+ // the super class.
+ bool can_sharpen_super_based_on_type = (invoke_type == kSuper) &&
+ (referrer_class != methods_class) && referrer_class->IsSubClass(methods_class) &&
+ resolved_method->GetMethodIndex() < methods_class->GetVTable()->GetLength() &&
+ (methods_class->GetVTable()->Get(resolved_method->GetMethodIndex()) == resolved_method);
+
+ if (kEnableFinalBasedSharpening && (can_sharpen_virtual_based_on_type ||
+ can_sharpen_super_based_on_type)) {
// Sharpen a virtual call into a direct call. The method_idx is into referrer's
// dex cache, check that this resolved method is where we expect it.
- CHECK(referrer_class->GetDexCache()->GetResolvedMethod(method_idx) == resolved_method)
- << PrettyMethod(resolved_method);
- stats_->VirtualMadeDirect(type);
- GetCodeAndMethodForDirectCall(type, kDirect, referrer_class, resolved_method,
- direct_code, direct_method);
- type = kDirect;
+ CHECK(referrer_class->GetDexCache()->GetResolvedMethod(target_method.dex_method_index) ==
+ resolved_method) << PrettyMethod(resolved_method);
+ if (update_stats) {
+ stats_->ResolvedMethod(invoke_type);
+ stats_->VirtualMadeDirect(invoke_type);
+ }
+ GetCodeAndMethodForDirectCall(invoke_type, kDirect, referrer_class, resolved_method,
+ direct_code, direct_method, update_stats);
+ invoke_type = kDirect;
return true;
- } else if(can_devirtualize && kEnableSharpening && kEnableVerifierBasedSharpening) {
- // If traditional sharpening fails, try the sharpening based on type information (Devirtualization)
- mirror::DexCache* dex_cache = mUnit->GetClassLinker()->FindDexCache(*ref_sharpen->first);
- mirror::ClassLoader* class_loader = soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader());
- mirror::AbstractMethod* concrete_method = mUnit->GetClassLinker()->ResolveMethod(
- *ref_sharpen->first, ref_sharpen->second, dex_cache, class_loader, NULL, kVirtual);
- CHECK(concrete_method != NULL);
- CHECK(!concrete_method->IsAbstract());
- // TODO: fix breakage in image patching to be able to devirtualize cases with different
- // resolved and concrete methods.
- if(resolved_method == concrete_method) {
- GetCodeAndMethodForDirectCall(type, kDirect, referrer_class, concrete_method, direct_code, direct_method);
- stats_->VirtualMadeDirect(type);
- type = kDirect;
- stats_->PreciseTypeDevirtualization();
+ }
+ const bool kEnableVerifierBasedSharpening = true;
+ if (kEnableVerifierBasedSharpening && (invoke_type == kVirtual ||
+ invoke_type == kInterface)) {
+ // Did the verifier record a more precise invoke target based on its type information?
+ const CompilerDriver::MethodReference caller_method(mUnit->GetDexFile(),
+ mUnit->GetDexMethodIndex());
+ const CompilerDriver::MethodReference* devirt_map_target =
+ verifier::MethodVerifier::GetDevirtMap(caller_method, dex_pc);
+ if (devirt_map_target != NULL) {
+ mirror::DexCache* target_dex_cache =
+ mUnit->GetClassLinker()->FindDexCache(*devirt_map_target->dex_file);
+ mirror::ClassLoader* class_loader =
+ soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader());
+ mirror::AbstractMethod* called_method =
+ mUnit->GetClassLinker()->ResolveMethod(*devirt_map_target->dex_file,
+ devirt_map_target->dex_method_index,
+ target_dex_cache, class_loader, NULL,
+ kVirtual);
+ CHECK(called_method != NULL);
+ CHECK(!called_method->IsAbstract());
+ GetCodeAndMethodForDirectCall(invoke_type, kDirect, referrer_class, called_method,
+ direct_code, direct_method, update_stats);
+ bool compiler_needs_dex_cache =
+ (GetCompilerBackend() == kPortable) ||
+ (GetCompilerBackend() == kQuick && instruction_set_ != kThumb2) ||
+ (direct_code == 0) || (direct_code == static_cast<unsigned int>(-1)) ||
+ (direct_method == 0) || (direct_method == static_cast<unsigned int>(-1));
+ if ((devirt_map_target->dex_file != target_method.dex_file) &&
+ compiler_needs_dex_cache) {
+ // We need to use the dex cache to find either the method or code, and the dex file
+ // containing the method isn't the one expected for the target method. Try to find
+ // the method within the expected target dex file.
+ // TODO: the -1 could be handled as direct code if the patching new the target dex
+ // file.
+ // TODO: quick only supports direct pointers with Thumb2.
+ // TODO: the following should be factored into a common helper routine to find
+ // one dex file's method within another.
+ const DexFile* dexfile = target_method.dex_file;
+ const DexFile* cm_dexfile =
+ called_method->GetDeclaringClass()->GetDexCache()->GetDexFile();
+ const DexFile::MethodId& cm_method_id =
+ cm_dexfile->GetMethodId(called_method->GetDexMethodIndex());
+ const char* cm_descriptor = cm_dexfile->StringByTypeIdx(cm_method_id.class_idx_);
+ const DexFile::StringId* descriptor = dexfile->FindStringId(cm_descriptor);
+ if (descriptor != NULL) {
+ const DexFile::TypeId* type_id =
+ dexfile->FindTypeId(dexfile->GetIndexForStringId(*descriptor));
+ if (type_id != NULL) {
+ const char* cm_name = cm_dexfile->GetMethodName(cm_method_id);
+ const DexFile::StringId* name = dexfile->FindStringId(cm_name);
+ if (name != NULL) {
+ uint16_t return_type_idx;
+ std::vector<uint16_t> param_type_idxs;
+ bool success = dexfile->CreateTypeList(&return_type_idx, &param_type_idxs,
+ cm_dexfile->GetMethodSignature(cm_method_id));
+ if (success) {
+ const DexFile::ProtoId* sig =
+ dexfile->FindProtoId(return_type_idx, param_type_idxs);
+ if (sig != NULL) {
+ const DexFile::MethodId* method_id = dexfile->FindMethodId(*type_id,
+ *name, *sig);
+ if (method_id != NULL) {
+ if (update_stats) {
+ stats_->ResolvedMethod(invoke_type);
+ stats_->VirtualMadeDirect(invoke_type);
+ stats_->PreciseTypeDevirtualization();
+ }
+ target_method.dex_method_index = dexfile->GetIndexForMethodId(*method_id);
+ invoke_type = kDirect;
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+ // TODO: the stats for direct code and method are off as we failed to find the direct
+ // method in the referring method's dex cache/file.
+ } else {
+ if (update_stats) {
+ stats_->ResolvedMethod(invoke_type);
+ stats_->VirtualMadeDirect(invoke_type);
+ stats_->PreciseTypeDevirtualization();
+ }
+ target_method = *devirt_map_target;
+ invoke_type = kDirect;
+ return true;
}
- stats_->ResolvedMethod(type);
- return true;
+ }
}
- else if (type == kSuper) {
+ if (invoke_type == kSuper) {
// Unsharpened super calls are suspicious so go slow-path.
} else {
- stats_->ResolvedMethod(type);
- GetCodeAndMethodForDirectCall(type, type, referrer_class, resolved_method,
- direct_code, direct_method);
+ // Sharpening failed so generate a regular resolved method dispatch.
+ if (update_stats) {
+ stats_->ResolvedMethod(invoke_type);
+ }
+ if (invoke_type == kVirtual || invoke_type == kSuper) {
+ vtable_idx = resolved_method->GetMethodIndex();
+ }
+ GetCodeAndMethodForDirectCall(invoke_type, invoke_type, referrer_class, resolved_method,
+ direct_code, direct_method, update_stats);
return true;
}
}
}
}
- // Clean up any exception left by method/type resolution
+ // Clean up any exception left by method/invoke_type resolution
if (soa.Self()->IsExceptionPending()) {
soa.Self()->ClearException();
}
- stats_->UnresolvedMethod(type);
+ if (update_stats) {
+ stats_->UnresolvedMethod(invoke_type);
+ }
return false; // Incomplete knowledge needs slow path.
}
+bool CompilerDriver::IsSafeCast(const MethodReference& mr, uint32_t dex_pc) {
+ bool result = verifier::MethodVerifier::IsSafeCast(mr, dex_pc);
+ if (result) {
+ stats_->SafeCast();
+ } else {
+ stats_->NotASafeCast();
+ }
+ return result;
+}
+
+
void CompilerDriver::AddCodePatch(const DexFile* dex_file,
uint32_t referrer_method_idx,
InvokeType referrer_invoke_type,
@@ -990,7 +1421,7 @@ class ParallelCompilationManager {
CHECK_NE(self->GetState(), kRunnable);
// Wait for all the worker threads to finish.
- thread_pool_->Wait(self);
+ thread_pool_->Wait(self, true, false);
}
private:
@@ -1404,10 +1835,13 @@ static const char* class_initializer_black_list[] = {
"Ljava/io/ObjectStreamClass;", // Calls to Class.forName -> java.io.FileDescriptor.
"Ljava/io/ObjectStreamConstants;", // Instance of non-image class SerializablePermission.
"Ljava/lang/ClassLoader$SystemClassLoader;", // Calls System.getProperty -> OsConstants.initConstants.
+ "Ljava/lang/HexStringParser;", // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
+ "Ljava/lang/ProcessManager;", // Calls Thread.currentThread.
"Ljava/lang/Runtime;", // Calls System.getProperty -> OsConstants.initConstants.
"Ljava/lang/System;", // Calls OsConstants.initConstants.
"Ljava/math/BigDecimal;", // Calls native ... -> java.math.NativeBN.BN_new().
"Ljava/math/BigInteger;", // Calls native ... -> java.math.NativeBN.BN_new().
+ "Ljava/math/Primality;", // Calls native ... -> java.math.NativeBN.BN_new().
"Ljava/math/Multiplication;", // Calls native ... -> java.math.NativeBN.BN_new().
"Ljava/net/InetAddress;", // Requires libcore.io.OsConstants.
"Ljava/net/Inet4Address;", // Sub-class of InetAddress.
@@ -1416,23 +1850,58 @@ static const char* class_initializer_black_list[] = {
"Ljava/nio/charset/Charset;", // Calls Charset.getDefaultCharset -> System.getProperty -> OsConstants.initConstants.
"Ljava/nio/charset/CharsetICU;", // Sub-class of Charset.
"Ljava/nio/charset/Charsets;", // Calls Charset.forName.
+ "Ljava/nio/charset/StandardCharsets;", // Calls OsConstants.initConstants.
+ "Ljava/security/AlgorithmParameterGenerator;", // Calls OsConstants.initConstants.
+ "Ljava/security/KeyPairGenerator$KeyPairGeneratorImpl;", // Calls OsConstants.initConstants.
"Ljava/security/KeyPairGenerator;", // Calls OsConstants.initConstants.
"Ljava/security/Security;", // Tries to do disk IO for "security.properties".
+ "Ljava/security/spec/RSAKeyGenParameterSpec;", // java.math.NativeBN.BN_new()
"Ljava/sql/Date;", // Calls OsConstants.initConstants.
+ "Ljava/sql/DriverManager;", // Calls OsConstants.initConstants.
+ "Ljava/sql/Time;", // Calls OsConstants.initConstants.
+ "Ljava/sql/Timestamp;", // Calls OsConstants.initConstants.
"Ljava/util/Date;", // Calls Date.<init> -> System.currentTimeMillis -> OsConstants.initConstants.
+ "Ljava/util/ListResourceBundle;", // Calls OsConstants.initConstants.
"Ljava/util/Locale;", // Calls System.getProperty -> OsConstants.initConstants.
+ "Ljava/util/PropertyResourceBundle;", // Calls OsConstants.initConstants.
+ "Ljava/util/ResourceBundle;", // Calls OsConstants.initConstants.
+ "Ljava/util/ResourceBundle$MissingBundle;", // Calls OsConstants.initConstants.
+ "Ljava/util/Scanner;", // regex.Pattern.compileImpl.
"Ljava/util/SimpleTimeZone;", // Sub-class of TimeZone.
"Ljava/util/TimeZone;", // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
"Ljava/util/concurrent/ConcurrentHashMap$Segment;", // Calls Runtime.getRuntime().availableProcessors().
+ "Ljava/util/concurrent/ConcurrentSkipListMap;", // Calls OsConstants.initConstants.
+ "Ljava/util/concurrent/Exchanger;", // Calls OsConstants.initConstants.
+ "Ljava/util/concurrent/ForkJoinPool;", // Calls OsConstants.initConstants.
+ "Ljava/util/concurrent/LinkedTransferQueue;", // Calls OsConstants.initConstants.
+ "Ljava/util/concurrent/Phaser;", // Calls OsConstants.initConstants.
+ "Ljava/util/concurrent/ScheduledThreadPoolExecutor;", // Calls AtomicLong.VMSupportsCS8()
+ "Ljava/util/concurrent/SynchronousQueue;", // Calls OsConstants.initConstants.
+ "Ljava/util/concurrent/atomic/AtomicLong;", // Calls AtomicLong.VMSupportsCS8()
"Ljava/util/logging/LogManager;", // Calls System.getProperty -> OsConstants.initConstants.
+ "Ljava/util/prefs/AbstractPreferences;", // Calls OsConstants.initConstants.
+ "Ljava/util/prefs/FilePreferencesImpl;", // Calls OsConstants.initConstants.
+ "Ljava/util/prefs/FilePreferencesFactoryImpl;", // Calls OsConstants.initConstants.
+ "Ljava/util/prefs/Preferences;", // Calls OsConstants.initConstants.
+ "Ljavax/crypto/KeyAgreement;", // Calls OsConstants.initConstants.
+ "Ljavax/crypto/KeyGenerator;", // Calls OsConstants.initConstants.
+ "Ljavax/security/cert/X509Certificate;", // Calls VMClassLoader.getBootClassPathSize.
+ "Ljavax/security/cert/X509Certificate$1;", // Calls VMClassLoader.getBootClassPathSize.
"Ljavax/microedition/khronos/egl/EGL10;", // Requires EGLContext.
"Ljavax/microedition/khronos/egl/EGLContext;", // Requires com.google.android.gles_jni.EGLImpl.
"Ljavax/net/ssl/HttpsURLConnection;", // Calls SSLSocketFactory.getDefault -> java.security.Security.getProperty.
+ "Ljavax/xml/datatype/DatatypeConstants;", // Calls OsConstants.initConstants.
+ "Ljavax/xml/datatype/FactoryFinder;", // Calls OsConstants.initConstants.
+ "Ljavax/xml/namespace/QName;", // Calls OsConstants.initConstants.
+ "Ljavax/xml/validation/SchemaFactoryFinder;", // Calls OsConstants.initConstants.
+ "Ljavax/xml/xpath/XPathConstants;", // Calls OsConstants.initConstants.
+ "Ljavax/xml/xpath/XPathFactoryFinder;", // Calls OsConstants.initConstants.
"Llibcore/icu/LocaleData;", // Requires java.util.Locale.
"Llibcore/icu/TimeZoneNames;", // Requires java.util.TimeZone.
"Llibcore/io/IoUtils;", // Calls Random.<init> -> System.currentTimeMillis -> FileDescriptor -> OsConstants.initConstants.
"Llibcore/io/OsConstants;", // Platform specific.
"Llibcore/net/MimeUtils;", // Calls libcore.net.MimeUtils.getContentTypesPropertiesStream -> System.getProperty.
+ "Llibcore/reflect/Types;", // Calls OsConstants.initConstants.
"Llibcore/util/ZoneInfo;", // Sub-class of TimeZone.
"Llibcore/util/ZoneInfoDB;", // Calls System.getenv -> OsConstants.initConstants.
"Lorg/apache/commons/logging/LogFactory;", // Calls System.getProperty.
@@ -1440,17 +1909,40 @@ static const char* class_initializer_black_list[] = {
"Lorg/apache/harmony/security/provider/cert/X509CertFactoryImpl;", // Requires java.nio.charsets.Charsets.
"Lorg/apache/harmony/security/provider/crypto/RandomBitsSupplier;", // Requires java.io.File.
"Lorg/apache/harmony/security/utils/AlgNameMapper;", // Requires java.util.Locale.
+ "Lorg/apache/harmony/security/pkcs10/CertificationRequest;", // Calls Thread.currentThread.
+ "Lorg/apache/harmony/security/pkcs10/CertificationRequestInfo;", // Calls Thread.currentThread.
+ "Lorg/apache/harmony/security/pkcs7/AuthenticatedAttributes;", // Calls Thread.currentThread.
+ "Lorg/apache/harmony/security/pkcs7/SignedData;", // Calls Thread.currentThread.
+ "Lorg/apache/harmony/security/pkcs7/SignerInfo;", // Calls Thread.currentThread.
+ "Lorg/apache/harmony/security/pkcs8/PrivateKeyInfo;", // Calls Thread.currentThread.
+ "Lorg/apache/harmony/security/provider/crypto/SHA1PRNG_SecureRandomImpl;", // Calls OsConstants.initConstants.
"Lorg/apache/harmony/security/x501/AttributeTypeAndValue;", // Calls IntegralToString.convertInt -> Thread.currentThread.
"Lorg/apache/harmony/security/x501/DirectoryString;", // Requires BigInteger.
"Lorg/apache/harmony/security/x501/Name;", // Requires org.apache.harmony.security.x501.AttributeTypeAndValue.
+ "Lorg/apache/harmony/security/x509/AccessDescription;", // Calls Thread.currentThread.
+ "Lorg/apache/harmony/security/x509/AuthorityKeyIdentifier;", // Calls Thread.currentThread.
+ "Lorg/apache/harmony/security/x509/CRLDistributionPoints;", // Calls Thread.currentThread.
"Lorg/apache/harmony/security/x509/Certificate;", // Requires org.apache.harmony.security.x509.TBSCertificate.
- "Lorg/apache/harmony/security/x509/TBSCertificate;", // Requires org.apache.harmony.security.x501.Name.
+ "Lorg/apache/harmony/security/x509/CertificateIssuer;", // Calls Thread.currentThread.
+ "Lorg/apache/harmony/security/x509/CertificateList;", // Calls Thread.currentThread.
+ "Lorg/apache/harmony/security/x509/DistributionPoint;", // Calls Thread.currentThread.
+ "Lorg/apache/harmony/security/x509/DistributionPointName;", // Calls Thread.currentThread.
"Lorg/apache/harmony/security/x509/EDIPartyName;", // Calls native ... -> java.math.NativeBN.BN_new().
"Lorg/apache/harmony/security/x509/GeneralName;", // Requires org.apache.harmony.security.x501.Name.
"Lorg/apache/harmony/security/x509/GeneralNames;", // Requires GeneralName.
+ "Lorg/apache/harmony/security/x509/GeneralSubtree;", // Calls Thread.currentThread.
+ "Lorg/apache/harmony/security/x509/GeneralSubtrees;", // Calls Thread.currentThread.
+ "Lorg/apache/harmony/security/x509/InfoAccessSyntax;", // Calls Thread.currentThread.
+ "Lorg/apache/harmony/security/x509/IssuingDistributionPoint;", // Calls Thread.currentThread.
+ "Lorg/apache/harmony/security/x509/NameConstraints;", // Calls Thread.currentThread.
+ "Lorg/apache/harmony/security/x509/TBSCertList$RevokedCertificate;", // Calls NativeBN.BN_new().
+ "Lorg/apache/harmony/security/x509/TBSCertList;", // Calls Thread.currentThread.
+ "Lorg/apache/harmony/security/x509/TBSCertificate;", // Requires org.apache.harmony.security.x501.Name.
"Lorg/apache/harmony/security/x509/Time;", // Calls native ... -> java.math.NativeBN.BN_new().
"Lorg/apache/harmony/security/x509/Validity;", // Requires x509.Time.
+ "Lorg/apache/harmony/security/x509/tsp/TSTInfo;", // Calls Thread.currentThread.
"Lorg/apache/harmony/xml/ExpatParser;", // Calls native ExpatParser.staticInitialize.
+ "Lorg/apache/harmony/xml/ExpatParser$EntityParser;", // Calls ExpatParser.staticInitialize.
"Lorg/apache/http/conn/params/ConnRouteParams;", // Requires java.util.Locale.
"Lorg/apache/http/conn/ssl/SSLSocketFactory;", // Calls java.security.Security.getProperty.
"Lorg/apache/http/conn/util/InetAddressUtils;", // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
@@ -1463,7 +1955,7 @@ static void InitializeClass(const ParallelCompilationManager* manager, size_t cl
mirror::ClassLoader* class_loader = soa.Decode<mirror::ClassLoader*>(manager->GetClassLoader());
const char* descriptor = manager->GetDexFile()->GetClassDescriptor(class_def);
mirror::Class* klass = manager->GetClassLinker()->FindClass(descriptor, class_loader);
- bool compiling_boot = Runtime::Current()->GetHeap()->GetSpaces().size() == 1;
+ bool compiling_boot = Runtime::Current()->GetHeap()->GetContinuousSpaces().size() == 1;
bool can_init_static_fields = compiling_boot &&
manager->GetCompiler()->IsImageClass(descriptor);
if (klass != NULL) {
@@ -1473,13 +1965,17 @@ static void InitializeClass(const ParallelCompilationManager* manager, size_t cl
// on a second thread the sub-class is initialized (holding its lock) after first initializing
// its parents, whose locks are acquired. This leads to a parent-to-child and a child-to-parent
// lock ordering and consequent potential deadlock.
- static Mutex lock1("Initializer lock", kMonitorLock);
- MutexLock mu(soa.Self(), lock1);
+ // We need to use an ObjectLock due to potential suspension in the interpreting code. Rather
+ // than use a special Object for the purpose we use the Class of java.lang.Class.
+ ObjectLock lock1(soa.Self(), klass->GetClass());
// The lock required to initialize the class.
ObjectLock lock2(soa.Self(), klass);
// Only try to initialize classes that were successfully verified.
if (klass->IsVerified()) {
manager->GetClassLinker()->EnsureInitialized(klass, false, can_init_static_fields);
+ if (soa.Self()->IsExceptionPending()) {
+ soa.Self()->GetException(NULL)->Dump();
+ }
if (!klass->IsInitialized()) {
if (can_init_static_fields) {
bool is_black_listed = false;
@@ -1517,7 +2013,7 @@ static void InitializeClass(const ParallelCompilationManager* manager, size_t cl
compiled_class = new CompiledClass(status);
manager->GetCompiler()->RecordClassStatus(ref, compiled_class);
} else {
- DCHECK_EQ(status, compiled_class->GetStatus());
+ DCHECK_GE(status, compiled_class->GetStatus()) << descriptor;
}
}
// Clear any class not found or verification exceptions.
@@ -1558,12 +2054,12 @@ void CompilerDriver::Compile(jobject class_loader, const std::vector<const DexFi
}
void CompilerDriver::CompileClass(const ParallelCompilationManager* manager, size_t class_def_index) {
- jobject class_loader = manager->GetClassLoader();
+ jobject jclass_loader = manager->GetClassLoader();
const DexFile& dex_file = *manager->GetDexFile();
const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
{
ScopedObjectAccess soa(Thread::Current());
- mirror::ClassLoader* class_loader = soa.Decode<mirror::ClassLoader*>(manager->GetClassLoader());
+ mirror::ClassLoader* class_loader = soa.Decode<mirror::ClassLoader*>(jclass_loader);
if (SkipClass(class_loader, dex_file, class_def)) {
return;
}
@@ -1578,6 +2074,13 @@ void CompilerDriver::CompileClass(const ParallelCompilationManager* manager, siz
// empty class, probably a marker interface
return;
}
+ // Can we run DEX-to-DEX compiler on this class ?
+ bool allow_dex_compilation;
+ {
+ ScopedObjectAccess soa(Thread::Current());
+ mirror::ClassLoader* class_loader = soa.Decode<mirror::ClassLoader*>(jclass_loader);
+ allow_dex_compilation = IsDexToDexCompilationAllowed(class_loader, dex_file, class_def);
+ }
ClassDataItemIterator it(dex_file, class_data);
// Skip fields
while (it.HasNextStaticField()) {
@@ -1599,7 +2102,7 @@ void CompilerDriver::CompileClass(const ParallelCompilationManager* manager, siz
previous_direct_method_idx = method_idx;
manager->GetCompiler()->CompileMethod(it.GetMethodCodeItem(), it.GetMemberAccessFlags(),
it.GetMethodInvokeType(class_def), class_def_index,
- method_idx, class_loader, dex_file);
+ method_idx, jclass_loader, dex_file, allow_dex_compilation);
it.Next();
}
// Compile virtual methods
@@ -1615,7 +2118,7 @@ void CompilerDriver::CompileClass(const ParallelCompilationManager* manager, siz
previous_virtual_method_idx = method_idx;
manager->GetCompiler()->CompileMethod(it.GetMethodCodeItem(), it.GetMemberAccessFlags(),
it.GetMethodInvokeType(class_def), class_def_index,
- method_idx, class_loader, dex_file);
+ method_idx, jclass_loader, dex_file, allow_dex_compilation);
it.Next();
}
DCHECK(!it.HasNext());
@@ -1631,7 +2134,8 @@ void CompilerDriver::CompileDexFile(jobject class_loader, const DexFile& dex_fil
void CompilerDriver::CompileMethod(const DexFile::CodeItem* code_item, uint32_t access_flags,
InvokeType invoke_type, uint32_t class_def_idx,
uint32_t method_idx, jobject class_loader,
- const DexFile& dex_file) {
+ const DexFile& dex_file,
+ bool allow_dex_to_dex_compilation) {
CompiledMethod* compiled_method = NULL;
uint64_t start_ns = NanoTime();
@@ -1641,7 +2145,8 @@ void CompilerDriver::CompileMethod(const DexFile::CodeItem* code_item, uint32_t
} else if ((access_flags & kAccAbstract) != 0) {
} else {
// In small mode we only compile image classes.
- bool dont_compile = Runtime::Current()->IsSmallMode() && ((image_classes_ == NULL) || (image_classes_->size() == 0));
+ bool dont_compile = (Runtime::Current()->IsSmallMode() &&
+ ((image_classes_.get() == NULL) || (image_classes_->size() == 0)));
// Don't compile class initializers, ever.
if (((access_flags & kAccConstructor) != 0) && ((access_flags & kAccStatic) != 0)) {
@@ -1650,11 +2155,30 @@ void CompilerDriver::CompileMethod(const DexFile::CodeItem* code_item, uint32_t
// Do compile small methods.
dont_compile = false;
}
-
if (!dont_compile) {
- compiled_method = (*compiler_)(*this, code_item, access_flags, invoke_type, class_def_idx,
+ bool use_sea = false;
+
+ if (Runtime::Current()->IsSeaIRMode()) {
+ use_sea = true;
+ }
+ if (use_sea) {
+ use_sea = (std::string::npos != PrettyMethod(method_idx, dex_file).find("fibonacci"));
+ }
+ if (!use_sea) {
+ compiled_method = (*compiler_)(*this, code_item, access_flags, invoke_type, class_def_idx,
method_idx, class_loader, dex_file);
+ } else {
+ compiled_method = (*sea_ir_compiler_)(*this, code_item, access_flags, invoke_type, class_def_idx,
+ method_idx, class_loader, dex_file);
+ }
CHECK(compiled_method != NULL) << PrettyMethod(method_idx, dex_file);
+ } else if (allow_dex_to_dex_compilation) {
+ // TODO: add a mode to disable DEX-to-DEX compilation ?
+ compiled_method = (*dex_to_dex_compiler_)(*this, code_item, access_flags,
+ invoke_type, class_def_idx,
+ method_idx, class_loader, dex_file);
+ // No native code is generated.
+ CHECK(compiled_method == NULL) << PrettyMethod(method_idx, dex_file);
}
}
uint64_t duration_ns = NanoTime() - start_ns;
diff --git a/src/compiler/driver/compiler_driver.h b/src/compiler/driver/compiler_driver.h
index 75d276d5b1..b37b74b042 100644
--- a/src/compiler/driver/compiler_driver.h
+++ b/src/compiler/driver/compiler_driver.h
@@ -39,7 +39,6 @@ class ParallelCompilationManager;
class DexCompilationUnit;
class TimingLogger;
-const uint32_t kDexPCNotReady = 0xFFFFFF;
enum CompilerBackend {
kQuick,
kPortable,
@@ -62,14 +61,16 @@ class CompilerTls {
class CompilerDriver {
public:
+ typedef std::set<std::string> DescriptorSet;
+
// Create a compiler targeting the requested "instruction_set".
// "image" should be true if image specific optimizations should be
// enabled. "image_classes" lets the compiler know what classes it
// can assume will be in the image, with NULL implying all available
// classes.
- explicit CompilerDriver(CompilerBackend compiler_backend, InstructionSet instruction_set, bool image,
+ explicit CompilerDriver(CompilerBackend compiler_backend, InstructionSet instruction_set,
+ bool image, DescriptorSet* image_classes,
size_t thread_count, bool support_debugging,
- const std::set<std::string>* image_classes,
bool dump_stats, bool dump_timings);
~CompilerDriver();
@@ -97,8 +98,22 @@ class CompilerDriver {
return image_;
}
+ DescriptorSet* GetImageClasses() const {
+ return image_classes_.get();
+ }
+
CompilerTls* GetTls();
+ // Generate the trampolines that are invoked by unresolved direct methods.
+ const std::vector<uint8_t>* CreatePortableResolutionTrampoline() const
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ const std::vector<uint8_t>* CreateQuickResolutionTrampoline() const
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ const std::vector<uint8_t>* CreateInterpreterToInterpreterEntry() const
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ const std::vector<uint8_t>* CreateInterpreterToQuickEntry() const
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
// A class is uniquely located by its DexFile and the class_defs_ table index into that DexFile
typedef std::pair<const DexFile*, uint32_t> ClassReference;
@@ -106,7 +121,22 @@ class CompilerDriver {
LOCKS_EXCLUDED(compiled_classes_lock_);
// A method is uniquely located by its DexFile and the method_ids_ table index into that DexFile
- typedef std::pair<const DexFile*, uint32_t> MethodReference;
+ struct MethodReference {
+ MethodReference(const DexFile* file, uint32_t index) : dex_file(file), dex_method_index(index) {
+ }
+ const DexFile* dex_file;
+ uint32_t dex_method_index;
+ };
+
+ struct MethodReferenceComparator {
+ bool operator()(MethodReference mr1, MethodReference mr2) const {
+ if (mr1.dex_file == mr2.dex_file) {
+ return mr1.dex_method_index < mr2.dex_method_index;
+ } else {
+ return mr1.dex_file < mr2.dex_file;
+ }
+ }
+ };
CompiledMethod* GetCompiledMethod(MethodReference ref) const
LOCKS_EXCLUDED(compiled_methods_lock_);
@@ -124,7 +154,9 @@ class CompilerDriver {
// Are runtime access checks necessary in the compiled code?
bool CanAccessTypeWithoutChecks(uint32_t referrer_idx, const DexFile& dex_file,
- uint32_t type_idx)
+ uint32_t type_idx, bool* type_known_final = NULL,
+ bool* type_known_abstract = NULL,
+ bool* equals_referrers_class = NULL)
LOCKS_EXCLUDED(Locks::mutator_lock_);
// Are runtime access and instantiable checks necessary in the code?
@@ -146,11 +178,13 @@ class CompilerDriver {
// Can we fastpath a interface, super class or virtual method call? Computes method's vtable
// index.
- bool ComputeInvokeInfo(uint32_t method_idx, uint32_t dex_pc,
- const DexCompilationUnit* mUnit, InvokeType& type, int& vtable_idx,
- uintptr_t& direct_code, uintptr_t& direct_method)
+ bool ComputeInvokeInfo(const DexCompilationUnit* mUnit, const uint32_t dex_pc,
+ InvokeType& type, MethodReference& target_method, int& vtable_idx,
+ uintptr_t& direct_code, uintptr_t& direct_method, bool update_stats)
LOCKS_EXCLUDED(Locks::mutator_lock_);
+ bool IsSafeCast(const MethodReference& mr, uint32_t dex_pc);
+
// Record patch information for later fix up.
void AddCodePatch(const DexFile* dex_file,
uint32_t referrer_method_idx,
@@ -169,6 +203,15 @@ class CompilerDriver {
void SetBitcodeFileName(std::string const& filename);
+ bool GetSupportBootImageFixup() const {
+ return support_boot_image_fixup_;
+ }
+
+ void SetSupportBootImageFixup(bool support_boot_image_fixup) {
+ support_boot_image_fixup_ = support_boot_image_fixup;
+ }
+
+
// TODO: remove these Elf wrappers when libart links against LLVM (when separate compiler library is gone)
bool WriteElf(const std::string& android_root,
bool is_host,
@@ -253,7 +296,7 @@ class CompilerDriver {
}
// Checks if class specified by type_idx is one of the image_classes_
- bool IsImageClass(const std::string& descriptor) const;
+ bool IsImageClass(const char* descriptor) const;
void RecordClassStatus(ClassReference ref, CompiledClass* compiled_class);
@@ -262,13 +305,16 @@ class CompilerDriver {
void GetCodeAndMethodForDirectCall(InvokeType type, InvokeType sharp_type,
mirror::Class* referrer_class,
mirror::AbstractMethod* method,
- uintptr_t& direct_code, uintptr_t& direct_method)
+ uintptr_t& direct_code, uintptr_t& direct_method,
+ bool update_stats)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
void PreCompile(jobject class_loader, const std::vector<const DexFile*>& dex_files,
ThreadPool& thread_pool, TimingLogger& timings)
LOCKS_EXCLUDED(Locks::mutator_lock_);
+ void LoadImageClasses(TimingLogger& timings);
+
// Attempt to resolve all type, methods, fields, and strings
// referenced from code in the dex file following PathClassLoader
// ordering semantics.
@@ -292,6 +338,10 @@ class CompilerDriver {
ThreadPool& thread_pool, TimingLogger& timings)
LOCKS_EXCLUDED(Locks::mutator_lock_, compiled_classes_lock_);
+ void UpdateImageClasses(TimingLogger& timings);
+ static void FindClinitImageClassesCallback(mirror::Object* object, void* arg)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
void Compile(jobject class_loader, const std::vector<const DexFile*>& dex_files,
ThreadPool& thread_pool, TimingLogger& timings);
void CompileDexFile(jobject class_loader, const DexFile& dex_file,
@@ -299,7 +349,8 @@ class CompilerDriver {
LOCKS_EXCLUDED(Locks::mutator_lock_);
void CompileMethod(const DexFile::CodeItem* code_item, uint32_t access_flags,
InvokeType invoke_type, uint32_t class_def_idx, uint32_t method_idx,
- jobject class_loader, const DexFile& dex_file)
+ jobject class_loader, const DexFile& dex_file,
+ bool allow_dex_to_dex_compilation)
LOCKS_EXCLUDED(compiled_methods_lock_);
static void CompileClass(const ParallelCompilationManager* context, size_t class_def_index)
@@ -321,12 +372,18 @@ class CompilerDriver {
mutable Mutex compiled_classes_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
ClassTable compiled_classes_ GUARDED_BY(compiled_classes_lock_);
- typedef SafeMap<const MethodReference, CompiledMethod*> MethodTable;
+ typedef SafeMap<const MethodReference, CompiledMethod*, MethodReferenceComparator> MethodTable;
// All method references that this compiler has compiled.
mutable Mutex compiled_methods_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
MethodTable compiled_methods_ GUARDED_BY(compiled_methods_lock_);
- bool image_;
+ const bool image_;
+
+ // If image_ is true, specifies the classes that will be included in
+ // the image. Note if image_classes_ is NULL, all classes are
+ // included in the image.
+ UniquePtr<DescriptorSet> image_classes_;
+
size_t thread_count_;
bool support_debugging_;
uint64_t start_ns_;
@@ -336,8 +393,6 @@ class CompilerDriver {
bool dump_stats_;
bool dump_timings_;
- const std::set<std::string>* image_classes_;
-
typedef void (*CompilerCallbackFn)(CompilerDriver& driver);
typedef MutexLock* (*CompilerMutexLockFn)(CompilerDriver& driver);
@@ -349,6 +404,9 @@ class CompilerDriver {
uint32_t class_dex_idx, uint32_t method_idx,
jobject class_loader, const DexFile& dex_file);
CompilerFn compiler_;
+ CompilerFn sea_ir_compiler_;
+
+ CompilerFn dex_to_dex_compiler_;
void* compiler_context_;
@@ -366,6 +424,8 @@ class CompilerDriver {
(const CompilerDriver& driver, const CompiledMethod* cm, const mirror::AbstractMethod* method);
CompilerGetMethodCodeAddrFn compiler_get_method_code_addr_;
+ bool support_boot_image_fixup_;
+
DISALLOW_COPY_AND_ASSIGN(CompilerDriver);
};
diff --git a/src/compiler/driver/compiler_driver_test.cc b/src/compiler/driver/compiler_driver_test.cc
index c87fefda16..abf8a9a3f7 100644
--- a/src/compiler/driver/compiler_driver_test.cc
+++ b/src/compiler/driver/compiler_driver_test.cc
@@ -23,10 +23,10 @@
#include "class_linker.h"
#include "common_test.h"
#include "dex_file.h"
-#include "heap.h"
+#include "gc/heap.h"
#include "mirror/class.h"
#include "mirror/class-inl.h"
-#include "mirror/dex_cache.h"
+#include "mirror/dex_cache-inl.h"
#include "mirror/abstract_method-inl.h"
#include "mirror/object_array-inl.h"
#include "mirror/object-inl.h"
diff --git a/src/compiler/driver/dex_compilation_unit.cc b/src/compiler/driver/dex_compilation_unit.cc
index 962df42a21..c7a4df6ea4 100644
--- a/src/compiler/driver/dex_compilation_unit.cc
+++ b/src/compiler/driver/dex_compilation_unit.cc
@@ -31,18 +31,17 @@ DexCompilationUnit::DexCompilationUnit(CompilationUnit* cu)
code_item_(cu->code_item),
class_def_idx_(cu->class_def_idx),
dex_method_idx_(cu->method_idx),
- access_flags_(cu->access_flags),
- symbol_(StringPrintf("dex_%s", MangleForJni(PrettyMethod(dex_method_idx_, *dex_file_)).c_str())) {
+ access_flags_(cu->access_flags) {
}
-DexCompilationUnit:: DexCompilationUnit(CompilationUnit* cu,
- jobject class_loader,
- ClassLinker* class_linker,
- const DexFile& dex_file,
- const DexFile::CodeItem* code_item,
- uint32_t class_def_idx,
- uint32_t method_idx,
- uint32_t access_flags)
+DexCompilationUnit::DexCompilationUnit(CompilationUnit* cu,
+ jobject class_loader,
+ ClassLinker* class_linker,
+ const DexFile& dex_file,
+ const DexFile::CodeItem* code_item,
+ uint32_t class_def_idx,
+ uint32_t method_idx,
+ uint32_t access_flags)
: cu_(cu),
class_loader_(class_loader),
class_linker_(class_linker),
@@ -50,8 +49,15 @@ DexCompilationUnit:: DexCompilationUnit(CompilationUnit* cu,
code_item_(code_item),
class_def_idx_(class_def_idx),
dex_method_idx_(method_idx),
- access_flags_(access_flags),
- symbol_(StringPrintf("dex_%s", MangleForJni(PrettyMethod(dex_method_idx_, *dex_file_)).c_str())) {
+ access_flags_(access_flags) {
+}
+
+const std::string& DexCompilationUnit::GetSymbol() {
+ if (symbol_.empty()) {
+ symbol_ = "dex_";
+ symbol_ += MangleForJni(PrettyMethod(dex_method_idx_, *dex_file_));
+ }
+ return symbol_;
}
} // namespace art
diff --git a/src/compiler/driver/dex_compilation_unit.h b/src/compiler/driver/dex_compilation_unit.h
index 0b90aaafdf..3c6129d642 100644
--- a/src/compiler/driver/dex_compilation_unit.h
+++ b/src/compiler/driver/dex_compilation_unit.h
@@ -92,9 +92,7 @@ class DexCompilationUnit {
return ((access_flags_ & kAccSynchronized) != 0);
}
- const std::string& GetSymbol() const {
- return symbol_;
- }
+ const std::string& GetSymbol();
private:
CompilationUnit* const cu_;
@@ -110,7 +108,7 @@ class DexCompilationUnit {
const uint32_t dex_method_idx_;
const uint32_t access_flags_;
- const std::string symbol_;
+ std::string symbol_;
};
} // namespace art
diff --git a/src/compiler/llvm/gbc_expander.cc b/src/compiler/llvm/gbc_expander.cc
index 99c8fd5ca7..bdf9aca68f 100644
--- a/src/compiler/llvm/gbc_expander.cc
+++ b/src/compiler/llvm/gbc_expander.cc
@@ -776,7 +776,8 @@ llvm::Value* GBCExpanderPass::EmitInvoke(llvm::CallInst& call_inst) {
art::InvokeType invoke_type =
static_cast<art::InvokeType>(LV2UInt(call_inst.getArgOperand(0)));
bool is_static = (invoke_type == art::kStatic);
- uint32_t callee_method_idx = LV2UInt(call_inst.getArgOperand(1));
+ art::CompilerDriver::MethodReference target_method(dex_compilation_unit_->GetDexFile(),
+ LV2UInt(call_inst.getArgOperand(1)));
// Load *this* actual parameter
llvm::Value* this_addr = (!is_static) ? call_inst.getArgOperand(3) : NULL;
@@ -785,18 +786,17 @@ llvm::Value* GBCExpanderPass::EmitInvoke(llvm::CallInst& call_inst) {
int vtable_idx = -1;
uintptr_t direct_code = 0;
uintptr_t direct_method = 0;
- // TODO: pass actual value of dex PC (instead of kDexPCNotready) needed by verifier based
- // sharpening after LLVM re-factoring is finished.
- bool is_fast_path = driver_->
- ComputeInvokeInfo(callee_method_idx, art::kDexPCNotReady, dex_compilation_unit_,
- invoke_type, vtable_idx, direct_code, direct_method);
-
+ bool is_fast_path = driver_->ComputeInvokeInfo(dex_compilation_unit_, dex_pc,
+ invoke_type, target_method,
+ vtable_idx,
+ direct_code, direct_method,
+ true);
// Load the method object
llvm::Value* callee_method_object_addr = NULL;
if (!is_fast_path) {
callee_method_object_addr =
- EmitCallRuntimeForCalleeMethodObjectAddr(callee_method_idx, invoke_type,
+ EmitCallRuntimeForCalleeMethodObjectAddr(target_method.dex_method_index, invoke_type,
this_addr, dex_pc, is_fast_path);
} else {
switch (invoke_type) {
@@ -809,7 +809,7 @@ llvm::Value* GBCExpanderPass::EmitInvoke(llvm::CallInst& call_inst) {
irb_.getJObjectTy());
} else {
callee_method_object_addr =
- EmitLoadSDCalleeMethodObjectAddr(callee_method_idx);
+ EmitLoadSDCalleeMethodObjectAddr(target_method.dex_method_index);
}
break;
@@ -826,7 +826,7 @@ llvm::Value* GBCExpanderPass::EmitInvoke(llvm::CallInst& call_inst) {
case art::kInterface:
callee_method_object_addr =
- EmitCallRuntimeForCalleeMethodObjectAddr(callee_method_idx,
+ EmitCallRuntimeForCalleeMethodObjectAddr(target_method.dex_method_index,
invoke_type, this_addr,
dex_pc, is_fast_path);
break;
@@ -844,7 +844,7 @@ llvm::Value* GBCExpanderPass::EmitInvoke(llvm::CallInst& call_inst) {
llvm::Value* code_addr;
llvm::Type* func_type = GetFunctionType(call_inst.getType(),
- callee_method_idx, is_static);
+ target_method.dex_method_index, is_static);
if (direct_code != 0u && direct_code != static_cast<uintptr_t>(-1)) {
code_addr =
irb_.CreateIntToPtr(irb_.getPtrEquivInt(direct_code),
diff --git a/src/compiler/llvm/llvm_compilation_unit.h b/src/compiler/llvm/llvm_compilation_unit.h
index d96e778912..857d924840 100644
--- a/src/compiler/llvm/llvm_compilation_unit.h
+++ b/src/compiler/llvm/llvm_compilation_unit.h
@@ -81,10 +81,10 @@ class LlvmCompilationUnit {
void SetCompilerDriver(CompilerDriver* driver) {
driver_ = driver;
}
- const DexCompilationUnit* GetDexCompilationUnit() {
+ DexCompilationUnit* GetDexCompilationUnit() {
return dex_compilation_unit_;
}
- void SetDexCompilationUnit(const DexCompilationUnit* dex_compilation_unit) {
+ void SetDexCompilationUnit(DexCompilationUnit* dex_compilation_unit) {
dex_compilation_unit_ = dex_compilation_unit;
}
@@ -113,7 +113,7 @@ class LlvmCompilationUnit {
UniquePtr<IntrinsicHelper> intrinsic_helper_;
UniquePtr<LLVMInfo> llvm_info_;
CompilerDriver* driver_;
- const DexCompilationUnit* dex_compilation_unit_;
+ DexCompilationUnit* dex_compilation_unit_;
std::string bitcode_filename_;
diff --git a/src/compiler/llvm/runtime_support_builder.cc b/src/compiler/llvm/runtime_support_builder.cc
index b4ddb55483..2be2ddf36f 100644
--- a/src/compiler/llvm/runtime_support_builder.cc
+++ b/src/compiler/llvm/runtime_support_builder.cc
@@ -16,7 +16,7 @@
#include "runtime_support_builder.h"
-#include "gc/card_table.h"
+#include "gc/accounting/card_table.h"
#include "ir_builder.h"
#include "monitor.h"
#include "mirror/object.h"
@@ -266,9 +266,11 @@ void RuntimeSupportBuilder::EmitMarkGCCard(::llvm::Value* value, ::llvm::Value*
irb_.getInt8Ty()->getPointerTo(),
kTBAAConstJObject);
Value* target_addr_int = irb_.CreatePtrToInt(target_addr, irb_.getPtrEquivIntTy());
- Value* card_no = irb_.CreateLShr(target_addr_int, irb_.getPtrEquivInt(CardTable::kCardShift));
+ Value* card_no = irb_.CreateLShr(target_addr_int,
+ irb_.getPtrEquivInt(gc::accounting::CardTable::kCardShift));
Value* card_table_entry = irb_.CreateGEP(card_table, card_no);
- irb_.CreateStore(irb_.getInt8(CardTable::kCardDirty), card_table_entry, kTBAARuntimeInfo);
+ irb_.CreateStore(irb_.getInt8(gc::accounting::CardTable::kCardDirty), card_table_entry,
+ kTBAARuntimeInfo);
irb_.CreateBr(bb_cont);
irb_.SetInsertPoint(bb_cont);
diff --git a/src/compiler/llvm/runtime_support_llvm.cc b/src/compiler/llvm/runtime_support_llvm.cc
index bd6b01b211..bff13f9dc9 100644
--- a/src/compiler/llvm/runtime_support_llvm.cc
+++ b/src/compiler/llvm/runtime_support_llvm.cc
@@ -24,6 +24,7 @@
#include "dex_instruction.h"
#include "mirror/abstract_method-inl.h"
#include "mirror/class-inl.h"
+#include "mirror/dex_cache-inl.h"
#include "mirror/field-inl.h"
#include "mirror/object.h"
#include "mirror/object-inl.h"
@@ -176,7 +177,7 @@ bool art_portable_is_exception_pending_from_code() {
}
void art_portable_throw_div_zero_from_code() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- ThrowArithmeticExceptionDivideByZero(Thread::Current());
+ ThrowArithmeticExceptionDivideByZero();
}
void art_portable_throw_array_bounds_from_code(int32_t index, int32_t length)
@@ -435,7 +436,7 @@ int32_t art_portable_set32_static_from_code(uint32_t field_idx, mirror::Abstract
return 0;
}
field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
- StaticPrimitiveWrite, sizeof(uint32_t));
+ StaticPrimitiveWrite, sizeof(uint32_t), true);
if (LIKELY(field != NULL)) {
field->Set32(field->GetDeclaringClass(), new_value);
return 0;
@@ -451,7 +452,7 @@ int32_t art_portable_set64_static_from_code(uint32_t field_idx, mirror::Abstract
return 0;
}
field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
- StaticPrimitiveWrite, sizeof(uint64_t));
+ StaticPrimitiveWrite, sizeof(uint64_t), true);
if (LIKELY(field != NULL)) {
field->Set64(field->GetDeclaringClass(), new_value);
return 0;
@@ -467,7 +468,7 @@ int32_t art_portable_set_obj_static_from_code(uint32_t field_idx, mirror::Abstra
return 0;
}
field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
- StaticObjectWrite, sizeof(mirror::Object*));
+ StaticObjectWrite, sizeof(mirror::Object*), true);
if (LIKELY(field != NULL)) {
field->SetObj(field->GetDeclaringClass(), new_value);
return 0;
@@ -482,7 +483,7 @@ int32_t art_portable_get32_static_from_code(uint32_t field_idx, mirror::Abstract
return field->Get32(field->GetDeclaringClass());
}
field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
- StaticPrimitiveRead, sizeof(uint32_t));
+ StaticPrimitiveRead, sizeof(uint32_t), true);
if (LIKELY(field != NULL)) {
return field->Get32(field->GetDeclaringClass());
}
@@ -496,7 +497,7 @@ int64_t art_portable_get64_static_from_code(uint32_t field_idx, mirror::Abstract
return field->Get64(field->GetDeclaringClass());
}
field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
- StaticPrimitiveRead, sizeof(uint64_t));
+ StaticPrimitiveRead, sizeof(uint64_t), true);
if (LIKELY(field != NULL)) {
return field->Get64(field->GetDeclaringClass());
}
@@ -510,7 +511,7 @@ mirror::Object* art_portable_get_obj_static_from_code(uint32_t field_idx, mirror
return field->GetObj(field->GetDeclaringClass());
}
field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
- StaticObjectRead, sizeof(mirror::Object*));
+ StaticObjectRead, sizeof(mirror::Object*), true);
if (LIKELY(field != NULL)) {
return field->GetObj(field->GetDeclaringClass());
}
@@ -526,7 +527,7 @@ int32_t art_portable_set32_instance_from_code(uint32_t field_idx, mirror::Abstra
return 0;
}
field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
- InstancePrimitiveWrite, sizeof(uint32_t));
+ InstancePrimitiveWrite, sizeof(uint32_t), true);
if (LIKELY(field != NULL)) {
field->Set32(obj, new_value);
return 0;
@@ -543,7 +544,7 @@ int32_t art_portable_set64_instance_from_code(uint32_t field_idx, mirror::Abstra
return 0;
}
field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
- InstancePrimitiveWrite, sizeof(uint64_t));
+ InstancePrimitiveWrite, sizeof(uint64_t), true);
if (LIKELY(field != NULL)) {
field->Set64(obj, new_value);
return 0;
@@ -560,7 +561,7 @@ int32_t art_portable_set_obj_instance_from_code(uint32_t field_idx, mirror::Abst
return 0;
}
field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
- InstanceObjectWrite, sizeof(mirror::Object*));
+ InstanceObjectWrite, sizeof(mirror::Object*), true);
if (LIKELY(field != NULL)) {
field->SetObj(obj, new_value);
return 0;
@@ -575,7 +576,7 @@ int32_t art_portable_get32_instance_from_code(uint32_t field_idx, mirror::Abstra
return field->Get32(obj);
}
field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
- InstancePrimitiveRead, sizeof(uint32_t));
+ InstancePrimitiveRead, sizeof(uint32_t), true);
if (LIKELY(field != NULL)) {
return field->Get32(obj);
}
@@ -589,7 +590,7 @@ int64_t art_portable_get64_instance_from_code(uint32_t field_idx, mirror::Abstra
return field->Get64(obj);
}
field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
- InstancePrimitiveRead, sizeof(uint64_t));
+ InstancePrimitiveRead, sizeof(uint64_t), true);
if (LIKELY(field != NULL)) {
return field->Get64(obj);
}
@@ -603,7 +604,7 @@ mirror::Object* art_portable_get_obj_instance_from_code(uint32_t field_idx, mirr
return field->GetObj(obj);
}
field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
- InstanceObjectRead, sizeof(mirror::Object*));
+ InstanceObjectRead, sizeof(mirror::Object*), true);
if (LIKELY(field != NULL)) {
return field->GetObj(obj);
}
diff --git a/src/compiler/sea_ir/frontend.cc b/src/compiler/sea_ir/frontend.cc
new file mode 100644
index 0000000000..d4e1c7e740
--- /dev/null
+++ b/src/compiler/sea_ir/frontend.cc
@@ -0,0 +1,81 @@
+
+#include <llvm/Support/Threading.h>
+
+#include "compiler/driver/compiler_driver.h"
+
+
+#include "compiler/llvm/llvm_compilation_unit.h"
+#include "compiler/dex/portable/mir_to_gbc.h"
+
+#include "leb128.h"
+#include "mirror/object.h"
+#include "runtime.h"
+#include "base/logging.h"
+
+#ifdef ART_SEA_IR_MODE
+#include "compiler/sea_ir/sea.h"
+#endif
+
+
+
+
+#ifdef ART_SEA_IR_MODE
+#include "compiler/sea_ir/sea.h"
+namespace art {
+
+static CompiledMethod* CompileMethodWithSeaIr(CompilerDriver& compiler,
+ const CompilerBackend compiler_backend,
+ const DexFile::CodeItem* code_item,
+ uint32_t access_flags, InvokeType invoke_type,
+ uint32_t class_def_idx, uint32_t method_idx,
+ jobject class_loader, const DexFile& dex_file
+#if defined(ART_USE_PORTABLE_COMPILER)
+ , llvm::LlvmCompilationUnit* llvm_compilation_unit
+#endif
+)
+{
+ VLOG(compiler) << "Compiling " << PrettyMethod(method_idx, dex_file) << "...";
+ sea_ir::SeaGraph* sg = sea_ir::SeaGraph::GetCurrentGraph();
+ sg->CompileMethod(code_item, class_def_idx, method_idx, dex_file);
+ sg->DumpSea("/tmp/temp.dot");
+ CHECK(0 && "No SEA compiled function exists yet.");
+ return NULL;
+}
+
+
+CompiledMethod* SeaIrCompileOneMethod(CompilerDriver& compiler,
+ const CompilerBackend backend,
+ const DexFile::CodeItem* code_item,
+ uint32_t access_flags,
+ InvokeType invoke_type,
+ uint32_t class_def_idx,
+ uint32_t method_idx,
+ jobject class_loader,
+ const DexFile& dex_file,
+ llvm::LlvmCompilationUnit* llvm_compilation_unit)
+{
+ return CompileMethodWithSeaIr(compiler, backend, code_item, access_flags, invoke_type, class_def_idx,
+ method_idx, class_loader, dex_file
+#if defined(ART_USE_PORTABLE_COMPILER)
+ , llvm_compilation_unit
+#endif
+
+ );
+}
+
+extern "C" art::CompiledMethod*
+ SeaIrCompileMethod(art::CompilerDriver& compiler,
+ const art::DexFile::CodeItem* code_item,
+ uint32_t access_flags, art::InvokeType invoke_type,
+ uint32_t class_def_idx, uint32_t method_idx, jobject class_loader,
+ const art::DexFile& dex_file)
+{
+ // TODO: check method fingerprint here to determine appropriate backend type. Until then, use build default
+ art::CompilerBackend backend = compiler.GetCompilerBackend();
+ return art::SeaIrCompileOneMethod(compiler, backend, code_item, access_flags, invoke_type,
+ class_def_idx, method_idx, class_loader, dex_file,
+ NULL /* use thread llvm_info */);
+}
+#endif
+
+} // end namespace art
diff --git a/src/compiler/sea_ir/sea.cc b/src/compiler/sea_ir/sea.cc
new file mode 100644
index 0000000000..e08558fa2d
--- /dev/null
+++ b/src/compiler/sea_ir/sea.cc
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "compiler/sea_ir/sea.h"
+#include "file_output_stream.h"
+
+
+
+namespace sea_ir {
+
+
+SeaGraph SeaGraph::graph_;
+int SeaNode::current_max_node_id_ = 0;
+
+SeaGraph* SeaGraph::GetCurrentGraph() {
+ return &sea_ir::SeaGraph::graph_;
+}
+
+void SeaGraph::DumpSea(std::string filename) const {
+ std::string result;
+ result += "digraph seaOfNodes {\n";
+ for(std::vector<Region*>::const_iterator cit = regions_.begin(); cit != regions_.end(); cit++) {
+ result += (*cit)->ToDot();
+ }
+ result += "}\n";
+ art::File* file = art::OS::OpenFile(filename.c_str(), true, true);
+ art::FileOutputStream fos(file);
+ fos.WriteFully(result.c_str(), result.size());
+ LOG(INFO) << "Written SEA string to file...";
+}
+
+void SeaGraph::CompileMethod(const art::DexFile::CodeItem* code_item,
+ uint32_t class_def_idx, uint32_t method_idx, const art::DexFile& dex_file) {
+ const uint16_t* code = code_item->insns_;
+ const size_t size_in_code_units = code_item->insns_size_in_code_units_;
+
+ Region* r = NULL;
+ // This maps target instruction pointers to their corresponding region objects.
+ std::map<const uint16_t*, Region*> target_regions;
+ size_t i = 0;
+
+ // Pass 1: Find the start instruction of basic blocks, as targets and flow-though of branches.
+ while (i < size_in_code_units) {
+ const art::Instruction* inst = art::Instruction::At(&code[i]);
+ if (inst->IsBranch()||inst->IsUnconditional()) {
+ int32_t offset = inst->GetTargetOffset();
+ if (target_regions.end() == target_regions.find(&code[i+offset])) {
+ Region* region = GetNewRegion();
+ target_regions.insert(std::pair<const uint16_t*, Region*>(&code[i+offset], region));
+ }
+ if (inst->IsFlowthrough() &&
+ (target_regions.end() == target_regions.find(&code[i+inst->SizeInCodeUnits()]))) {
+ Region* region = GetNewRegion();
+ target_regions.insert(std::pair<const uint16_t*, Region*>(&code[i+inst->SizeInCodeUnits()], region));
+ }
+ }
+ i += inst->SizeInCodeUnits();
+ }
+
+
+ // Pass 2: Assign instructions to region nodes and
+ // assign branches their control flow successors.
+ i = 0;
+ r = GetNewRegion();
+ sea_ir::SeaNode* last_node = NULL;
+ sea_ir::SeaNode* node = NULL;
+ while (i < size_in_code_units) {
+ const art::Instruction* inst = art::Instruction::At(&code[i]); //TODO: find workaround for this
+ last_node = node;
+ node = new sea_ir::SeaNode(inst);
+
+ if (inst->IsBranch() || inst->IsUnconditional()) {
+ int32_t offset = inst->GetTargetOffset();
+ std::map<const uint16_t*, Region*>::iterator it = target_regions.find(&code[i+offset]);
+ DCHECK(it != target_regions.end());
+ node->AddSuccessor(it->second);
+ }
+
+ std::map<const uint16_t*, Region*>::iterator it = target_regions.find(&code[i]);
+ if (target_regions.end() != it) {
+ // Get the already created region because this is a branch target.
+ Region* nextRegion = it->second;
+ if (last_node->GetInstruction()->IsBranch() && last_node->GetInstruction()->IsFlowthrough()) {
+ last_node->AddSuccessor(nextRegion);
+
+ }
+ r = nextRegion;
+ }
+
+ LOG(INFO) << inst->GetDexPc(code) << "*** " << inst->DumpString(&dex_file)
+ << " region:" <<r->StringId() << std::endl;
+ r->AddChild(node);
+ i += inst->SizeInCodeUnits();
+ }
+
+}
+
+
+Region* SeaGraph::GetNewRegion() {
+ Region* new_region = new Region();
+ AddRegion(new_region);
+ return new_region;
+}
+
+void SeaGraph::AddRegion(Region* r) {
+ DCHECK(r) << "Tried to add NULL region to SEA graph.";
+ regions_.push_back(r);
+}
+void Region::AddChild(sea_ir::SeaNode* instruction) {
+ DCHECK(inst) << "Tried to add NULL instruction to region node.";
+ instructions_.push_back(instruction);
+}
+
+SeaNode* Region::GetLastChild() const {
+ if (instructions_.size()>0) {
+ return instructions_.back();
+ }
+ return NULL;
+}
+
+std::string SeaNode::ToDot() const {
+ std::string node = "// Instruction: \n" + StringId() +
+ " [label=\"" + instruction_->DumpString(NULL) + "\"];\n";
+
+ for(std::vector<SeaNode*>::const_iterator cit = successors_.begin();
+ cit != successors_.end(); cit++) {
+ DCHECK(NULL != *cit) << "Null successor found for SeaNode" << StringId() << ".";
+ node += StringId() + " -> " + (*cit)->StringId() + ";\n\n";
+ }
+ return node;
+}
+
+std::string SeaNode::StringId() const {
+ std::stringstream ss;
+ ss << id_;
+ return ss.str();
+}
+
+std::string Region::ToDot() const {
+ std::string result = "// Region: \n" +
+ StringId() + " [label=\"region " + StringId() + "\"];";
+
+ for(std::vector<SeaNode*>::const_iterator cit = instructions_.begin();
+ cit != instructions_.end(); cit++) {
+ result += (*cit)->ToDot();
+ result += StringId() + " -> " + (*cit)->StringId() + ";\n";
+ }
+
+ result += "// End Region.\n";
+ return result;
+}
+
+void SeaNode::AddSuccessor(SeaNode* successor) {
+ DCHECK(successor) << "Tried to add NULL successor to SEA node.";
+ successors_.push_back(successor);
+ return;
+}
+
+} // end namespace
diff --git a/src/compiler/sea_ir/sea.h b/src/compiler/sea_ir/sea.h
new file mode 100644
index 0000000000..0ebd4d02d4
--- /dev/null
+++ b/src/compiler/sea_ir/sea.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "dex_file.h"
+#include "dex_instruction.h"
+
+#ifndef SEA_IR_H_
+#define SEA_IR_H_
+
+#include <set>
+#include <map>
+
+namespace sea_ir {
+
+
+class SeaNode {
+ public:
+ explicit SeaNode(const art::Instruction* in):id_(GetNewId()), instruction_(in), successors_() {};
+ explicit SeaNode():id_(GetNewId()), instruction_(NULL) {};
+ void AddSuccessor(SeaNode* successor);
+ const art::Instruction* GetInstruction() {
+ DCHECK(NULL != instruction_);
+ return instruction_;
+ }
+ std::string StringId() const;
+ // Returns a dot language formatted string representing the node and
+ // (by convention) outgoing edges, so that the composition of theToDot() of all nodes
+ // builds a complete dot graph (without prolog and epilog though).
+ virtual std::string ToDot() const;
+ virtual ~SeaNode(){};
+
+ protected:
+ // Returns the id of the current block as string
+
+ static int GetNewId() {
+ return current_max_node_id_++;
+ }
+
+
+ private:
+ const int id_;
+ const art::Instruction* const instruction_;
+ std::vector<sea_ir::SeaNode*> successors_;
+ static int current_max_node_id_;
+};
+
+
+
+class Region : public SeaNode {
+ public:
+ explicit Region():SeaNode() {}
+ void AddChild(sea_ir::SeaNode* instruction);
+ SeaNode* GetLastChild() const;
+
+ // Returns a dot language formatted string representing the node and
+ // (by convention) outgoing edges, so that the composition of theToDot() of all nodes
+ // builds a complete dot graph (without prolog and epilog though).
+ virtual std::string ToDot() const;
+
+ private:
+ std::vector<sea_ir::SeaNode*> instructions_;
+};
+
+
+
+class SeaGraph {
+ public:
+ static SeaGraph* GetCurrentGraph();
+ void CompileMethod(const art::DexFile::CodeItem* code_item,
+ uint32_t class_def_idx, uint32_t method_idx, const art::DexFile& dex_file);
+ // Returns a string representation of the region and its Instruction children
+ void DumpSea(std::string filename) const;
+ /*** Static helper functions follow: ***/
+ static int ParseInstruction(const uint16_t* code_ptr,
+ art::DecodedInstruction* decoded_instruction);
+ static bool IsInstruction(const uint16_t* code_ptr);
+
+ private:
+ // Registers the parameter as a child region of the SeaGraph instance
+ void AddRegion(Region* r);
+ // Returns new region and registers it with the SeaGraph instance
+ Region* GetNewRegion();
+ static SeaGraph graph_;
+ std::vector<Region*> regions_;
+};
+
+
+} // end namespace sea_ir
+#endif
diff --git a/src/compiler/stubs/portable/stubs.cc b/src/compiler/stubs/portable/stubs.cc
new file mode 100644
index 0000000000..db551bf368
--- /dev/null
+++ b/src/compiler/stubs/portable/stubs.cc
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2011 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 "compiler/stubs/stubs.h"
+#include "jni_internal.h"
+#include "oat/utils/arm/assembler_arm.h"
+#include "oat/utils/mips/assembler_mips.h"
+#include "oat/utils/x86/assembler_x86.h"
+#include "oat/runtime/oat_support_entrypoints.h"
+#include "stack_indirect_reference_table.h"
+#include "sirt_ref.h"
+
+#define __ assembler->
+
+namespace art {
+
+namespace arm {
+const std::vector<uint8_t>* CreatePortableResolutionTrampoline() {
+ UniquePtr<ArmAssembler> assembler(static_cast<ArmAssembler*>(Assembler::Create(kArm)));
+ RegList save = (1 << R0) | (1 << R1) | (1 << R2) | (1 << R3) | (1 << LR);
+
+ __ PushList(save);
+ __ LoadFromOffset(kLoadWord, R12, TR, ENTRYPOINT_OFFSET(pPortableResolutionTrampolineFromCode));
+ __ mov(R3, ShifterOperand(TR)); // Pass Thread::Current() in R3
+ __ mov(R2, ShifterOperand(SP)); // Pass sp for Method** callee_addr
+ __ IncreaseFrameSize(12); // 3 words of space for alignment
+ // Call to resolution trampoline (callee, receiver, callee_addr, Thread*)
+ __ blx(R12);
+ __ mov(R12, ShifterOperand(R0)); // Save code address returned into R12
+ __ DecreaseFrameSize(12);
+ __ PopList(save);
+ __ cmp(R12, ShifterOperand(0));
+ __ bx(R12, NE); // If R12 != 0 tail call method's code
+ __ bx(LR); // Return to caller to handle exception
+
+ assembler->EmitSlowPaths();
+ size_t cs = assembler->CodeSize();
+ UniquePtr<std::vector<uint8_t> > resolution_trampoline(new std::vector<uint8_t>(cs));
+ MemoryRegion code(&(*resolution_trampoline)[0], resolution_trampoline->size());
+ assembler->FinalizeInstructions(code);
+
+ return resolution_trampoline.release();
+}
+} // namespace arm
+
+namespace mips {
+const std::vector<uint8_t>* CreatePortableResolutionTrampoline() {
+ UniquePtr<MipsAssembler> assembler(static_cast<MipsAssembler*>(Assembler::Create(kMips)));
+ // Build frame and save argument registers and RA.
+ __ AddConstant(SP, SP, -32);
+ __ StoreToOffset(kStoreWord, RA, SP, 28);
+ __ StoreToOffset(kStoreWord, A3, SP, 12);
+ __ StoreToOffset(kStoreWord, A2, SP, 8);
+ __ StoreToOffset(kStoreWord, A1, SP, 4);
+ __ StoreToOffset(kStoreWord, A0, SP, 0);
+
+ __ LoadFromOffset(kLoadWord, T9, S1,
+ ENTRYPOINT_OFFSET(pPortableResolutionTrampolineFromCode));
+ __ Move(A3, S1); // Pass Thread::Current() in A3
+ __ Move(A2, SP); // Pass SP for Method** callee_addr
+ __ Jalr(T9); // Call to resolution trampoline (callee, receiver, callee_addr, Thread*)
+
+ // Restore frame, argument registers, and RA.
+ __ LoadFromOffset(kLoadWord, A0, SP, 0);
+ __ LoadFromOffset(kLoadWord, A1, SP, 4);
+ __ LoadFromOffset(kLoadWord, A2, SP, 8);
+ __ LoadFromOffset(kLoadWord, A3, SP, 12);
+ __ LoadFromOffset(kLoadWord, RA, SP, 28);
+ __ AddConstant(SP, SP, 32);
+
+ Label resolve_fail;
+ __ EmitBranch(V0, ZERO, &resolve_fail, true);
+ __ Jr(V0); // If V0 != 0 tail call method's code
+ __ Bind(&resolve_fail, false);
+ __ Jr(RA); // Return to caller to handle exception
+
+ assembler->EmitSlowPaths();
+ size_t cs = assembler->CodeSize();
+ UniquePtr<std::vector<uint8_t> > resolution_trampoline(new std::vector<uint8_t>(cs));
+ MemoryRegion code(&(*resolution_trampoline)[0], resolution_trampoline->size());
+ assembler->FinalizeInstructions(code);
+
+ return resolution_trampoline.release();
+}
+} // namespace mips
+
+namespace x86 {
+const std::vector<uint8_t>* CreatePortableResolutionTrampoline() {
+ UniquePtr<X86Assembler> assembler(static_cast<X86Assembler*>(Assembler::Create(kX86)));
+
+ __ pushl(EBP);
+ __ movl(EBP, ESP); // save ESP
+ __ subl(ESP, Immediate(8)); // Align stack
+ __ movl(EAX, Address(EBP, 8)); // Method* called
+ __ leal(EDX, Address(EBP, 8)); // Method** called_addr
+ __ fs()->pushl(Address::Absolute(Thread::SelfOffset())); // pass thread
+ __ pushl(EDX); // pass called_addr
+ __ pushl(ECX); // pass receiver
+ __ pushl(EAX); // pass called
+ // Call to resolve method.
+ __ Call(ThreadOffset(ENTRYPOINT_OFFSET(pPortableResolutionTrampolineFromCode)),
+ X86ManagedRegister::FromCpuRegister(ECX));
+ __ leave();
+
+ Label resolve_fail; // forward declaration
+ __ cmpl(EAX, Immediate(0));
+ __ j(kEqual, &resolve_fail);
+ __ jmp(EAX);
+ // Tail call to intended method.
+ __ Bind(&resolve_fail);
+ __ ret();
+
+ assembler->EmitSlowPaths();
+ size_t cs = assembler->CodeSize();
+ UniquePtr<std::vector<uint8_t> > resolution_trampoline(new std::vector<uint8_t>(cs));
+ MemoryRegion code(&(*resolution_trampoline)[0], resolution_trampoline->size());
+ assembler->FinalizeInstructions(code);
+
+ return resolution_trampoline.release();
+}
+} // namespace x86
+
+} // namespace art
diff --git a/src/compiler/stubs/quick/stubs.cc b/src/compiler/stubs/quick/stubs.cc
new file mode 100644
index 0000000000..a8e691f35b
--- /dev/null
+++ b/src/compiler/stubs/quick/stubs.cc
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2011 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 "compiler/stubs/stubs.h"
+#include "jni_internal.h"
+#include "oat/utils/arm/assembler_arm.h"
+#include "oat/utils/mips/assembler_mips.h"
+#include "oat/utils/x86/assembler_x86.h"
+#include "oat/runtime/oat_support_entrypoints.h"
+#include "stack_indirect_reference_table.h"
+#include "sirt_ref.h"
+
+#define __ assembler->
+
+namespace art {
+
+namespace arm {
+const std::vector<uint8_t>* CreateQuickResolutionTrampoline() {
+ UniquePtr<ArmAssembler> assembler(static_cast<ArmAssembler*>(Assembler::Create(kArm)));
+ // | Out args |
+ // | Method* | <- SP on entry
+ // | LR | return address into caller
+ // | ... | callee saves
+ // | R3 | possible argument
+ // | R2 | possible argument
+ // | R1 | possible argument
+ // | R0 | junk on call to QuickResolutionTrampolineFromCode, holds result Method*
+ // | Method* | Callee save Method* set up by QuickResoltuionTrampolineFromCode
+ // Save callee saves and ready frame for exception delivery
+ RegList save = (1 << R1) | (1 << R2) | (1 << R3) | (1 << R5) | (1 << R6) | (1 << R7) | (1 << R8) |
+ (1 << R10) | (1 << R11) | (1 << LR);
+ // TODO: enable when GetCalleeSaveMethod is available at stub generation time
+ // DCHECK_EQ(save, Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs)->GetCoreSpillMask());
+ __ PushList(save);
+ __ LoadFromOffset(kLoadWord, R12, TR, ENTRYPOINT_OFFSET(pQuickResolutionTrampolineFromCode));
+ __ mov(R3, ShifterOperand(TR)); // Pass Thread::Current() in R3
+ __ IncreaseFrameSize(8); // 2 words of space for alignment
+ __ mov(R2, ShifterOperand(SP)); // Pass SP
+ // Call to resolution trampoline (method_idx, receiver, sp, Thread*)
+ __ blx(R12);
+ __ mov(R12, ShifterOperand(R0)); // Save code address returned into R12
+ // Restore registers which may have been modified by GC, "R0" will hold the Method*
+ __ DecreaseFrameSize(4);
+ __ PopList((1 << R0) | save);
+ __ bx(R12); // Leaf call to method's code
+ __ bkpt(0);
+
+ assembler->EmitSlowPaths();
+ size_t cs = assembler->CodeSize();
+ UniquePtr<std::vector<uint8_t> > resolution_trampoline(new std::vector<uint8_t>(cs));
+ MemoryRegion code(&(*resolution_trampoline)[0], resolution_trampoline->size());
+ assembler->FinalizeInstructions(code);
+
+ return resolution_trampoline.release();
+}
+
+const std::vector<uint8_t>* CreateInterpreterToInterpreterEntry() {
+ UniquePtr<ArmAssembler> assembler(static_cast<ArmAssembler*>(Assembler::Create(kArm)));
+
+ __ LoadFromOffset(kLoadWord, PC, R0, ENTRYPOINT_OFFSET(pInterpreterToInterpreterEntry));
+ __ bkpt(0);
+
+ size_t cs = assembler->CodeSize();
+ UniquePtr<std::vector<uint8_t> > entry_stub(new std::vector<uint8_t>(cs));
+ MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
+ assembler->FinalizeInstructions(code);
+
+ return entry_stub.release();
+}
+
+const std::vector<uint8_t>* CreateInterpreterToQuickEntry() {
+ UniquePtr<ArmAssembler> assembler(static_cast<ArmAssembler*>(Assembler::Create(kArm)));
+
+ __ LoadFromOffset(kLoadWord, PC, R0, ENTRYPOINT_OFFSET(pInterpreterToQuickEntry));
+ __ bkpt(0);
+
+ size_t cs = assembler->CodeSize();
+ UniquePtr<std::vector<uint8_t> > entry_stub(new std::vector<uint8_t>(cs));
+ MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
+ assembler->FinalizeInstructions(code);
+
+ return entry_stub.release();
+}
+} // namespace arm
+
+namespace mips {
+const std::vector<uint8_t>* CreateQuickResolutionTrampoline() {
+ UniquePtr<MipsAssembler> assembler(static_cast<MipsAssembler*>(Assembler::Create(kMips)));
+ // | Out args |
+ // | Method* | <- SP on entry
+ // | RA | return address into caller
+ // | ... | callee saves
+ // | A3 | possible argument
+ // | A2 | possible argument
+ // | A1 | possible argument
+ // | A0/Method* | Callee save Method* set up by UnresolvedDirectMethodTrampolineFromCode
+ // Save callee saves and ready frame for exception delivery
+ __ AddConstant(SP, SP, -64);
+ __ StoreToOffset(kStoreWord, RA, SP, 60);
+ __ StoreToOffset(kStoreWord, FP, SP, 56);
+ __ StoreToOffset(kStoreWord, GP, SP, 52);
+ __ StoreToOffset(kStoreWord, S7, SP, 48);
+ __ StoreToOffset(kStoreWord, S6, SP, 44);
+ __ StoreToOffset(kStoreWord, S5, SP, 40);
+ __ StoreToOffset(kStoreWord, S4, SP, 36);
+ __ StoreToOffset(kStoreWord, S3, SP, 32);
+ __ StoreToOffset(kStoreWord, S2, SP, 28);
+ __ StoreToOffset(kStoreWord, A3, SP, 12);
+ __ StoreToOffset(kStoreWord, A2, SP, 8);
+ __ StoreToOffset(kStoreWord, A1, SP, 4);
+
+ __ LoadFromOffset(kLoadWord, T9, S1, ENTRYPOINT_OFFSET(pQuickResolutionTrampolineFromCode));
+ __ Move(A3, S1); // Pass Thread::Current() in A3
+ __ Move(A2, SP); // Pass SP for Method** callee_addr
+ __ Jalr(T9); // Call to resolution trampoline (method_idx, receiver, sp, Thread*)
+
+ // Restore registers which may have been modified by GC
+ __ LoadFromOffset(kLoadWord, A0, SP, 0);
+ __ LoadFromOffset(kLoadWord, A1, SP, 4);
+ __ LoadFromOffset(kLoadWord, A2, SP, 8);
+ __ LoadFromOffset(kLoadWord, A3, SP, 12);
+ __ LoadFromOffset(kLoadWord, S2, SP, 28);
+ __ LoadFromOffset(kLoadWord, S3, SP, 32);
+ __ LoadFromOffset(kLoadWord, S4, SP, 36);
+ __ LoadFromOffset(kLoadWord, S5, SP, 40);
+ __ LoadFromOffset(kLoadWord, S6, SP, 44);
+ __ LoadFromOffset(kLoadWord, S7, SP, 48);
+ __ LoadFromOffset(kLoadWord, GP, SP, 52);
+ __ LoadFromOffset(kLoadWord, FP, SP, 56);
+ __ LoadFromOffset(kLoadWord, RA, SP, 60);
+ __ AddConstant(SP, SP, 64);
+
+ __ Move(T9, V0); // Put method's code in T9
+ __ Jr(T9); // Leaf call to method's code
+
+ __ Break();
+
+ assembler->EmitSlowPaths();
+ size_t cs = assembler->CodeSize();
+ UniquePtr<std::vector<uint8_t> > resolution_trampoline(new std::vector<uint8_t>(cs));
+ MemoryRegion code(&(*resolution_trampoline)[0], resolution_trampoline->size());
+ assembler->FinalizeInstructions(code);
+
+ return resolution_trampoline.release();
+}
+
+const std::vector<uint8_t>* CreateInterpreterToInterpreterEntry() {
+ UniquePtr<MipsAssembler> assembler(static_cast<MipsAssembler*>(Assembler::Create(kMips)));
+
+ __ LoadFromOffset(kLoadWord, T9, A0, ENTRYPOINT_OFFSET(pInterpreterToInterpreterEntry));
+ __ Jr(T9);
+ __ Break();
+
+ size_t cs = assembler->CodeSize();
+ UniquePtr<std::vector<uint8_t> > entry_stub(new std::vector<uint8_t>(cs));
+ MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
+ assembler->FinalizeInstructions(code);
+
+ return entry_stub.release();
+}
+
+const std::vector<uint8_t>* CreateInterpreterToQuickEntry() {
+ UniquePtr<MipsAssembler> assembler(static_cast<MipsAssembler*>(Assembler::Create(kMips)));
+
+ __ LoadFromOffset(kLoadWord, T9, A0, ENTRYPOINT_OFFSET(pInterpreterToInterpreterEntry));
+ __ Jr(T9);
+ __ Break();
+
+ size_t cs = assembler->CodeSize();
+ UniquePtr<std::vector<uint8_t> > entry_stub(new std::vector<uint8_t>(cs));
+ MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
+ assembler->FinalizeInstructions(code);
+
+ return entry_stub.release();
+}
+} // namespace mips
+
+namespace x86 {
+const std::vector<uint8_t>* CreateQuickResolutionTrampoline() {
+ UniquePtr<X86Assembler> assembler(static_cast<X86Assembler*>(Assembler::Create(kX86)));
+ // Set up the callee save frame to conform with Runtime::CreateCalleeSaveMethod(kRefsAndArgs)
+ // return address
+ __ pushl(EDI);
+ __ pushl(ESI);
+ __ pushl(EBP);
+ __ pushl(EBX);
+ __ pushl(EDX);
+ __ pushl(ECX);
+ __ pushl(EAX); // <-- callee save Method* to go here
+ __ movl(EDX, ESP); // save ESP
+ __ fs()->pushl(Address::Absolute(Thread::SelfOffset())); // pass Thread*
+ __ pushl(EDX); // pass ESP for Method*
+ __ pushl(ECX); // pass receiver
+ __ pushl(EAX); // pass Method*
+
+ // Call to resolve method.
+ __ Call(ThreadOffset(ENTRYPOINT_OFFSET(pQuickResolutionTrampolineFromCode)),
+ X86ManagedRegister::FromCpuRegister(ECX));
+
+ __ movl(EDI, EAX); // save code pointer in EDI
+ __ addl(ESP, Immediate(16)); // Pop arguments
+ __ popl(EAX); // Restore args.
+ __ popl(ECX);
+ __ popl(EDX);
+ __ popl(EBX);
+ __ popl(EBP); // Restore callee saves.
+ __ popl(ESI);
+ // Swap EDI callee save with code pointer
+ __ xchgl(EDI, Address(ESP, 0));
+ // Tail call to intended method.
+ __ ret();
+
+ assembler->EmitSlowPaths();
+ size_t cs = assembler->CodeSize();
+ UniquePtr<std::vector<uint8_t> > resolution_trampoline(new std::vector<uint8_t>(cs));
+ MemoryRegion code(&(*resolution_trampoline)[0], resolution_trampoline->size());
+ assembler->FinalizeInstructions(code);
+
+ return resolution_trampoline.release();
+}
+
+const std::vector<uint8_t>* CreateInterpreterToInterpreterEntry() {
+ UniquePtr<X86Assembler> assembler(static_cast<X86Assembler*>(Assembler::Create(kX86)));
+
+ __ fs()->jmp(Address::Absolute(ThreadOffset(ENTRYPOINT_OFFSET(pInterpreterToInterpreterEntry))));
+
+ size_t cs = assembler->CodeSize();
+ UniquePtr<std::vector<uint8_t> > entry_stub(new std::vector<uint8_t>(cs));
+ MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
+ assembler->FinalizeInstructions(code);
+
+ return entry_stub.release();
+}
+
+const std::vector<uint8_t>* CreateInterpreterToQuickEntry() {
+ UniquePtr<X86Assembler> assembler(static_cast<X86Assembler*>(Assembler::Create(kX86)));
+
+ __ fs()->jmp(Address::Absolute(ThreadOffset(ENTRYPOINT_OFFSET(pInterpreterToQuickEntry))));
+
+ size_t cs = assembler->CodeSize();
+ UniquePtr<std::vector<uint8_t> > entry_stub(new std::vector<uint8_t>(cs));
+ MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
+ assembler->FinalizeInstructions(code);
+
+ return entry_stub.release();
+}
+} // namespace x86
+
+} // namespace art
diff --git a/src/compiler/stubs/stubs.h b/src/compiler/stubs/stubs.h
new file mode 100644
index 0000000000..ebe761df35
--- /dev/null
+++ b/src/compiler/stubs/stubs.h
@@ -0,0 +1,59 @@
+/*
+ * 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_COMPILER_STUBS_STUBS_H_
+#define ART_SRC_COMPILER_STUBS_STUBS_H_
+
+#include "runtime.h"
+
+namespace art {
+
+namespace arm {
+const std::vector<uint8_t>* CreatePortableResolutionTrampoline()
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+const std::vector<uint8_t>* CreateQuickResolutionTrampoline()
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+const std::vector<uint8_t>* CreateInterpreterToInterpreterEntry()
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+const std::vector<uint8_t>* CreateInterpreterToQuickEntry()
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+}
+
+namespace mips {
+const std::vector<uint8_t>* CreatePortableResolutionTrampoline()
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+const std::vector<uint8_t>* CreateQuickResolutionTrampoline()
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+const std::vector<uint8_t>* CreateInterpreterToInterpreterEntry()
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+const std::vector<uint8_t>* CreateInterpreterToQuickEntry()
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+}
+
+namespace x86 {
+const std::vector<uint8_t>* CreatePortableResolutionTrampoline()
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+const std::vector<uint8_t>* CreateQuickResolutionTrampoline()
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+const std::vector<uint8_t>* CreateInterpreterToInterpreterEntry()
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+const std::vector<uint8_t>* CreateInterpreterToQuickEntry()
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+}
+
+} // namespace art
+
+#endif // ART_SRC_COMPILER_STUBS_STUBS_H_
diff --git a/src/debugger.cc b/src/debugger.cc
index d7fac4300b..f2a10f02b6 100644
--- a/src/debugger.cc
+++ b/src/debugger.cc
@@ -24,9 +24,9 @@
#include "class_linker-inl.h"
#include "dex_file-inl.h"
#include "dex_instruction.h"
-#include "gc/card_table-inl.h"
-#include "gc/large_object_space.h"
-#include "gc/space.h"
+#include "gc/accounting/card_table-inl.h"
+#include "gc/space/large_object_space.h"
+#include "gc/space/space-inl.h"
#include "invoke_arg_array_builder.h"
#include "jdwp/object_registry.h"
#include "mirror/abstract_method-inl.h"
@@ -1691,6 +1691,7 @@ JDWP::JdwpError Dbg::GetThreadStatus(JDWP::ObjectId thread_id, JDWP::JdwpThreadS
case kWaitingForDebuggerSuspension: *pThreadStatus = JDWP::TS_WAIT; break;
case kWaitingForDebuggerToAttach: *pThreadStatus = JDWP::TS_WAIT; break;
case kWaitingForGcToComplete: *pThreadStatus = JDWP::TS_WAIT; break;
+ case kWaitingForCheckPointsToRun: *pThreadStatus = JDWP::TS_WAIT; break;
case kWaitingForJniOnLoad: *pThreadStatus = JDWP::TS_WAIT; break;
case kWaitingForSignalCatcherOutput: *pThreadStatus = JDWP::TS_WAIT; break;
case kWaitingInMainDebuggerLoop: *pThreadStatus = JDWP::TS_WAIT; break;
@@ -3137,7 +3138,7 @@ void Dbg::DdmSendHeapInfo(HpifWhen reason) {
* [u4]: current number of objects allocated
*/
uint8_t heap_count = 1;
- Heap* heap = Runtime::Current()->GetHeap();
+ gc::Heap* heap = Runtime::Current()->GetHeap();
std::vector<uint8_t> bytes;
JDWP::Append4BE(bytes, heap_count);
JDWP::Append4BE(bytes, 1); // Heap id (bogus; we only have one heap).
@@ -3416,17 +3417,16 @@ void Dbg::DdmSendHeapSegments(bool native) {
// Send a series of heap segment chunks.
HeapChunkContext context((what == HPSG_WHAT_MERGED_OBJECTS), native);
if (native) {
- // TODO: enable when bionic has moved to dlmalloc 2.8.5
- // dlmalloc_inspect_all(HeapChunkContext::HeapChunkCallback, &context);
- UNIMPLEMENTED(WARNING) << "Native heap send heap segments";
+ dlmalloc_inspect_all(HeapChunkContext::HeapChunkCallback, &context);
} else {
- Heap* heap = Runtime::Current()->GetHeap();
- const Spaces& spaces = heap->GetSpaces();
+ gc::Heap* heap = Runtime::Current()->GetHeap();
+ const std::vector<gc::space::ContinuousSpace*>& spaces = heap->GetContinuousSpaces();
Thread* self = Thread::Current();
ReaderMutexLock mu(self, *Locks::heap_bitmap_lock_);
- for (Spaces::const_iterator cur = spaces.begin(); cur != spaces.end(); ++cur) {
- if ((*cur)->IsAllocSpace()) {
- (*cur)->AsAllocSpace()->Walk(HeapChunkContext::HeapChunkCallback, &context);
+ typedef std::vector<gc::space::ContinuousSpace*>::const_iterator It;
+ for (It cur = spaces.begin(), end = spaces.end(); cur != end; ++cur) {
+ if ((*cur)->IsDlMallocSpace()) {
+ (*cur)->AsDlMallocSpace()->Walk(HeapChunkContext::HeapChunkCallback, &context);
}
}
// Walk the large objects, these are not in the AllocSpace.
diff --git a/src/dex2oat.cc b/src/dex2oat.cc
index ad751d0b7f..7cf54b4eee 100644
--- a/src/dex2oat.cc
+++ b/src/dex2oat.cc
@@ -30,6 +30,8 @@
#include "class_linker.h"
#include "compiler/driver/compiler_driver.h"
#include "dex_file-inl.h"
+#include "gc/space/image_space.h"
+#include "gc/space/space-inl.h"
#include "image_writer.h"
#include "leb128.h"
#include "mirror/abstract_method-inl.h"
@@ -161,18 +163,15 @@ class Dex2Oat {
}
- // Make a list of descriptors for classes to include in the image
- std::set<std::string>* GetImageClassDescriptors(const char* image_classes_filename)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ // Reads the class names (java.lang.Object) and returns as set of class descriptors (Ljava/lang/Object;)
+ CompilerDriver::DescriptorSet* ReadImageClasses(const char* image_classes_filename) {
UniquePtr<std::ifstream> image_classes_file(new std::ifstream(image_classes_filename, std::ifstream::in));
if (image_classes_file.get() == NULL) {
LOG(ERROR) << "Failed to open image classes file " << image_classes_filename;
return NULL;
}
- // Load all the classes specified in the file
- ClassLinker* class_linker = runtime_->GetClassLinker();
- Thread* self = Thread::Current();
+ UniquePtr<CompilerDriver::DescriptorSet> image_classes(new CompilerDriver::DescriptorSet);
while (image_classes_file->good()) {
std::string dot;
std::getline(*image_classes_file.get(), dot);
@@ -180,51 +179,9 @@ class Dex2Oat {
continue;
}
std::string descriptor(DotToDescriptor(dot.c_str()));
- SirtRef<mirror::Class> klass(self, class_linker->FindSystemClass(descriptor.c_str()));
- if (klass.get() == NULL) {
- LOG(WARNING) << "Failed to find class " << descriptor;
- Thread::Current()->ClearException();
- }
+ image_classes->insert(descriptor);
}
image_classes_file->close();
-
- // Resolve exception classes referenced by the loaded classes. The catch logic assumes
- // exceptions are resolved by the verifier when there is a catch block in an interested method.
- // Do this here so that exception classes appear to have been specified image classes.
- std::set<std::pair<uint16_t, const DexFile*> > unresolved_exception_types;
- SirtRef<mirror::Class> java_lang_Throwable(self,
- class_linker->FindSystemClass("Ljava/lang/Throwable;"));
- do {
- unresolved_exception_types.clear();
- class_linker->VisitClasses(ResolveCatchBlockExceptionsClassVisitor,
- &unresolved_exception_types);
- typedef std::set<std::pair<uint16_t, const DexFile*> >::const_iterator It; // TODO: C++0x auto
- for (It it = unresolved_exception_types.begin(),
- end = unresolved_exception_types.end();
- it != end; ++it) {
- uint16_t exception_type_idx = it->first;
- const DexFile* dex_file = it->second;
- mirror::DexCache* dex_cache = class_linker->FindDexCache(*dex_file);
- mirror:: ClassLoader* class_loader = NULL;
- SirtRef<mirror::Class> klass(self, class_linker->ResolveType(*dex_file, exception_type_idx,
- dex_cache, class_loader));
- if (klass.get() == NULL) {
- const DexFile::TypeId& type_id = dex_file->GetTypeId(exception_type_idx);
- const char* descriptor = dex_file->GetTypeDescriptor(type_id);
- LOG(FATAL) << "Failed to resolve class " << descriptor;
- }
- DCHECK(java_lang_Throwable->IsAssignableFrom(klass.get()));
- }
- // Resolving exceptions may load classes that reference more exceptions, iterate until no
- // more are found
- } while (!unresolved_exception_types.empty());
-
- // We walk the roots looking for classes so that we'll pick up the
- // above classes plus any classes them depend on such super
- // classes, interfaces, and the required ClassLinker roots.
- UniquePtr<ImageWriter::DescriptorSet> image_classes(new ImageWriter::DescriptorSet);
- class_linker->VisitClasses(RecordImageClassesVisitor, image_classes.get());
- CHECK_NE(image_classes->size(), 0U);
return image_classes.release();
}
@@ -236,7 +193,7 @@ class Dex2Oat {
File* oat_file,
const std::string& bitcode_filename,
bool image,
- const ImageWriter::DescriptorSet* image_classes,
+ UniquePtr<CompilerDriver::DescriptorSet>& image_classes,
bool dump_stats,
bool dump_timings)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
@@ -260,9 +217,9 @@ class Dex2Oat {
UniquePtr<CompilerDriver> driver(new CompilerDriver(compiler_backend_,
instruction_set_,
image,
+ image_classes.release(),
thread_count_,
support_debugging_,
- image_classes,
dump_stats,
dump_timings));
@@ -280,11 +237,11 @@ class Dex2Oat {
std::string image_file_location;
uint32_t image_file_location_oat_checksum = 0;
uint32_t image_file_location_oat_data_begin = 0;
- Heap* heap = Runtime::Current()->GetHeap();
- if (heap->GetSpaces().size() > 1) {
- ImageSpace* image_space = heap->GetImageSpace();
+ if (!driver->IsImage()) {
+ gc::space::ImageSpace* image_space = Runtime::Current()->GetHeap()->GetImageSpace();
image_file_location_oat_checksum = image_space->GetImageHeader().GetOatChecksum();
- image_file_location_oat_data_begin = reinterpret_cast<uint32_t>(image_space->GetImageHeader().GetOatDataBegin());
+ image_file_location_oat_data_begin =
+ reinterpret_cast<uint32_t>(image_space->GetImageHeader().GetOatDataBegin());
image_file_location = image_space->GetImageFilename();
if (host_prefix != NULL && StartsWith(image_file_location, host_prefix->c_str())) {
image_file_location = image_file_location.substr(host_prefix->size());
@@ -292,6 +249,13 @@ class Dex2Oat {
}
std::vector<uint8_t> oat_contents;
+ // TODO: change ElfWriterQuick to not require the creation of oat_contents. The old pre-mclinker
+ // OatWriter streamed directly to disk. The new could can be adapted to do it as follows:
+ // 1.) use first pass of OatWriter to calculate size of oat structure,
+ // 2.) call ElfWriterQuick with pointer to OatWriter instead of contents,
+ // 3.) have ElfWriterQuick call back to OatWriter to stream generate the output directly in
+ // place in the elf file.
+ oat_contents.reserve(5 * MB);
VectorOutputStream vector_output_stream(oat_file->GetPath(), oat_contents);
if (!OatWriter::Create(vector_output_stream,
dex_files,
@@ -313,7 +277,6 @@ class Dex2Oat {
bool CreateImageFile(const std::string& image_filename,
uintptr_t image_base,
- ImageWriter::DescriptorSet* image_classes,
const std::string& oat_filename,
const std::string& oat_location,
const CompilerDriver& compiler)
@@ -321,8 +284,8 @@ class Dex2Oat {
uintptr_t oat_data_begin;
{
// ImageWriter is scoped so it can free memory before doing FixupElf
- ImageWriter image_writer(image_classes);
- if (!image_writer.Write(image_filename, image_base, oat_filename, oat_location, compiler)) {
+ ImageWriter image_writer(compiler);
+ if (!image_writer.Write(image_filename, image_base, oat_filename, oat_location)) {
LOG(ERROR) << "Failed to create image file " << image_filename;
return false;
}
@@ -373,72 +336,6 @@ class Dex2Oat {
return true;
}
- static void ResolveExceptionsForMethod(MethodHelper* mh,
- std::set<std::pair<uint16_t, const DexFile*> >& exceptions_to_resolve)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- const DexFile::CodeItem* code_item = mh->GetCodeItem();
- if (code_item == NULL) {
- return; // native or abstract method
- }
- if (code_item->tries_size_ == 0) {
- return; // nothing to process
- }
- const byte* encoded_catch_handler_list = DexFile::GetCatchHandlerData(*code_item, 0);
- size_t num_encoded_catch_handlers = DecodeUnsignedLeb128(&encoded_catch_handler_list);
- for (size_t i = 0; i < num_encoded_catch_handlers; i++) {
- int32_t encoded_catch_handler_size = DecodeSignedLeb128(&encoded_catch_handler_list);
- bool has_catch_all = false;
- if (encoded_catch_handler_size <= 0) {
- encoded_catch_handler_size = -encoded_catch_handler_size;
- has_catch_all = true;
- }
- for (int32_t j = 0; j < encoded_catch_handler_size; j++) {
- uint16_t encoded_catch_handler_handlers_type_idx =
- DecodeUnsignedLeb128(&encoded_catch_handler_list);
- // Add to set of types to resolve if not already in the dex cache resolved types
- if (!mh->IsResolvedTypeIdx(encoded_catch_handler_handlers_type_idx)) {
- exceptions_to_resolve.insert(
- std::pair<uint16_t, const DexFile*>(encoded_catch_handler_handlers_type_idx,
- &mh->GetDexFile()));
- }
- // ignore address associated with catch handler
- DecodeUnsignedLeb128(&encoded_catch_handler_list);
- }
- if (has_catch_all) {
- // ignore catch all address
- DecodeUnsignedLeb128(&encoded_catch_handler_list);
- }
- }
- }
-
- static bool ResolveCatchBlockExceptionsClassVisitor(mirror::Class* c, void* arg)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- std::set<std::pair<uint16_t, const DexFile*> >* exceptions_to_resolve =
- reinterpret_cast<std::set<std::pair<uint16_t, const DexFile*> >*>(arg);
- MethodHelper mh;
- for (size_t i = 0; i < c->NumVirtualMethods(); ++i) {
- mirror::AbstractMethod* m = c->GetVirtualMethod(i);
- mh.ChangeMethod(m);
- ResolveExceptionsForMethod(&mh, *exceptions_to_resolve);
- }
- for (size_t i = 0; i < c->NumDirectMethods(); ++i) {
- mirror::AbstractMethod* m = c->GetDirectMethod(i);
- mh.ChangeMethod(m);
- ResolveExceptionsForMethod(&mh, *exceptions_to_resolve);
- }
- return true;
- }
-
- static bool RecordImageClassesVisitor(mirror::Class* klass, void* arg)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- ImageWriter::DescriptorSet* image_classes = reinterpret_cast<ImageWriter::DescriptorSet*>(arg);
- if (klass->IsArrayClass() || klass->IsPrimitive()) {
- return true;
- }
- image_classes->insert(ClassHelper(klass).GetDescriptor());
- return true;
- }
-
// Appends to dex_files any elements of class_path that it doesn't already
// contain. This will open those dex files as necessary.
static void OpenClassPathFiles(const std::string& class_path, std::vector<const DexFile*>& dex_files) {
@@ -561,12 +458,14 @@ class WatchDog {
private:
static void* CallBack(void* arg) {
WatchDog* self = reinterpret_cast<WatchDog*>(arg);
+ ::art::SetThreadName("dex2oat watch dog");
self->Wait();
return NULL;
}
static void Message(char severity, const std::string& message) {
- // TODO: Remove when we switch to LOG when we can guarantee it won't prevent shutdown in error cases.
+ // TODO: Remove when we switch to LOG when we can guarantee it won't prevent shutdown in error
+ // cases.
fprintf(stderr, "dex2oat%s %c %d %d %s\n",
kIsDebugBuild ? "d" : "",
severity,
@@ -587,10 +486,13 @@ class WatchDog {
void Wait() {
bool warning = true;
CHECK_GT(kWatchDogTimeoutSeconds, kWatchDogWarningSeconds);
+ // TODO: tune the multiplier for GC verification, the following is just to make the timeout
+ // large.
+ int64_t multiplier = gc::kDesiredHeapVerification > gc::kVerifyAllFast ? 100 : 1;
timespec warning_ts;
- InitTimeSpec(true, CLOCK_REALTIME, kWatchDogWarningSeconds * 1000, 0, &warning_ts);
+ InitTimeSpec(true, CLOCK_REALTIME, multiplier * kWatchDogWarningSeconds * 1000, 0, &warning_ts);
timespec timeout_ts;
- InitTimeSpec(true, CLOCK_REALTIME, kWatchDogTimeoutSeconds * 1000, 0, &timeout_ts);
+ InitTimeSpec(true, CLOCK_REALTIME, multiplier * kWatchDogTimeoutSeconds * 1000, 0, &timeout_ts);
const char* reason = "dex2oat watch dog thread waiting";
CHECK_WATCH_DOG_PTHREAD_CALL(pthread_mutex_lock, (&mutex_), reason);
while (!shutting_down_) {
@@ -627,12 +529,14 @@ class WatchDog {
bool is_watch_dog_enabled_;
bool shutting_down_;
- // TODO: Switch to Mutex when we can guarantee it won't prevent shutdown in error cases
+ // TODO: Switch to Mutex when we can guarantee it won't prevent shutdown in error cases.
pthread_mutex_t mutex_;
pthread_cond_t cond_;
pthread_attr_t attr_;
pthread_t pthread_;
};
+const unsigned int WatchDog::kWatchDogWarningSeconds;
+const unsigned int WatchDog::kWatchDogTimeoutSeconds;
static int dex2oat(int argc, char** argv) {
InitLogging(argv);
@@ -919,8 +823,14 @@ static int dex2oat(int argc, char** argv) {
options.push_back(std::make_pair("-small", reinterpret_cast<void*>(NULL)));
#endif // ART_SMALL_MODE
+
+#ifdef ART_SEA_IR_MODE
+ options.push_back(std::make_pair("-sea_ir", reinterpret_cast<void*>(NULL)));
+#endif
+
+
Dex2Oat* p_dex2oat;
- if (!Dex2Oat::Create(&p_dex2oat, options, compiler_backend, instruction_set, thread_count,
+ if (!Dex2Oat::Create(&p_dex2oat, options, compiler_backend, instruction_set, thread_count,
support_debugging)) {
LOG(ERROR) << "Failed to create dex2oat";
return EXIT_FAILURE;
@@ -934,9 +844,9 @@ static int dex2oat(int argc, char** argv) {
ScopedObjectAccess soa(Thread::Current());
// If --image-classes was specified, calculate the full list of classes to include in the image
- UniquePtr<ImageWriter::DescriptorSet> image_classes(NULL);
+ UniquePtr<CompilerDriver::DescriptorSet> image_classes(NULL);
if (image_classes_filename != NULL) {
- image_classes.reset(dex2oat->GetImageClassDescriptors(image_classes_filename));
+ image_classes.reset(dex2oat->ReadImageClasses(image_classes_filename));
if (image_classes.get() == NULL) {
LOG(ERROR) << "Failed to create list of image classes from " << image_classes_filename;
return EXIT_FAILURE;
@@ -992,7 +902,7 @@ static int dex2oat(int argc, char** argv) {
oat_file.get(),
bitcode_filename,
image,
- image_classes.get(),
+ image_classes,
dump_stats,
dump_timings));
@@ -1057,7 +967,6 @@ static int dex2oat(int argc, char** argv) {
Thread::Current()->TransitionFromRunnableToSuspended(kNative);
bool image_creation_success = dex2oat->CreateImageFile(image_filename,
image_base,
- image_classes.get(),
oat_unstripped,
oat_location,
*compiler.get());
diff --git a/src/dex_file.cc b/src/dex_file.cc
index 0f0bed4db9..80465f2fed 100644
--- a/src/dex_file.cc
+++ b/src/dex_file.cc
@@ -108,6 +108,28 @@ int DexFile::GetPermissions() const {
}
}
+bool DexFile::IsReadOnly() const {
+ return GetPermissions() == PROT_READ;
+}
+
+bool DexFile::EnableWrite(uint8_t* addr, size_t length) const {
+ CHECK(IsReadOnly());
+ if (mem_map_.get() == NULL) {
+ return false;
+ } else {
+ return mem_map_->ProtectRegion(addr, length, PROT_READ | PROT_WRITE);
+ }
+}
+
+bool DexFile::DisableWrite(uint8_t* addr, size_t length) const {
+ CHECK(!IsReadOnly());
+ if (mem_map_.get() == NULL) {
+ return false;
+ } else {
+ return mem_map_->ProtectRegion(addr, length, PROT_READ);
+ }
+}
+
const DexFile* DexFile::OpenFile(const std::string& filename,
const std::string& location,
bool verify) {
@@ -373,10 +395,10 @@ const DexFile::FieldId* DexFile::FindFieldId(const DexFile::TypeId& declaring_kl
const uint16_t class_idx = GetIndexForTypeId(declaring_klass);
const uint32_t name_idx = GetIndexForStringId(name);
const uint16_t type_idx = GetIndexForTypeId(type);
- uint32_t lo = 0;
- uint32_t hi = NumFieldIds() - 1;
+ int32_t lo = 0;
+ int32_t hi = NumFieldIds() - 1;
while (hi >= lo) {
- uint32_t mid = (hi + lo) / 2;
+ int32_t mid = (hi + lo) / 2;
const DexFile::FieldId& field = GetFieldId(mid);
if (class_idx > field.class_idx_) {
lo = mid + 1;
@@ -408,10 +430,10 @@ const DexFile::MethodId* DexFile::FindMethodId(const DexFile::TypeId& declaring_
const uint16_t class_idx = GetIndexForTypeId(declaring_klass);
const uint32_t name_idx = GetIndexForStringId(name);
const uint16_t proto_idx = GetIndexForProtoId(signature);
- uint32_t lo = 0;
- uint32_t hi = NumMethodIds() - 1;
+ int32_t lo = 0;
+ int32_t hi = NumMethodIds() - 1;
while (hi >= lo) {
- uint32_t mid = (hi + lo) / 2;
+ int32_t mid = (hi + lo) / 2;
const DexFile::MethodId& method = GetMethodId(mid);
if (class_idx > method.class_idx_) {
lo = mid + 1;
@@ -436,15 +458,35 @@ const DexFile::MethodId* DexFile::FindMethodId(const DexFile::TypeId& declaring_
return NULL;
}
-const DexFile::StringId* DexFile::FindStringId(const std::string& string) const {
- uint32_t lo = 0;
- uint32_t hi = NumStringIds() - 1;
+const DexFile::StringId* DexFile::FindStringId(const char* string) const {
+ int32_t lo = 0;
+ int32_t hi = NumStringIds() - 1;
+ while (hi >= lo) {
+ int32_t mid = (hi + lo) / 2;
+ uint32_t length;
+ const DexFile::StringId& str_id = GetStringId(mid);
+ const char* str = GetStringDataAndLength(str_id, &length);
+ int compare = CompareModifiedUtf8ToModifiedUtf8AsUtf16CodePointValues(string, str);
+ if (compare > 0) {
+ lo = mid + 1;
+ } else if (compare < 0) {
+ hi = mid - 1;
+ } else {
+ return &str_id;
+ }
+ }
+ return NULL;
+}
+
+const DexFile::StringId* DexFile::FindStringId(const uint16_t* string) const {
+ int32_t lo = 0;
+ int32_t hi = NumStringIds() - 1;
while (hi >= lo) {
- uint32_t mid = (hi + lo) / 2;
+ int32_t mid = (hi + lo) / 2;
uint32_t length;
const DexFile::StringId& str_id = GetStringId(mid);
const char* str = GetStringDataAndLength(str_id, &length);
- int compare = CompareModifiedUtf8ToModifiedUtf8AsUtf16CodePointValues(string.c_str(), str);
+ int compare = CompareModifiedUtf8ToUtf16AsCodePointValues(str, string);
if (compare > 0) {
lo = mid + 1;
} else if (compare < 0) {
@@ -457,10 +499,10 @@ const DexFile::StringId* DexFile::FindStringId(const std::string& string) const
}
const DexFile::TypeId* DexFile::FindTypeId(uint32_t string_idx) const {
- uint32_t lo = 0;
- uint32_t hi = NumTypeIds() - 1;
+ int32_t lo = 0;
+ int32_t hi = NumTypeIds() - 1;
while (hi >= lo) {
- uint32_t mid = (hi + lo) / 2;
+ int32_t mid = (hi + lo) / 2;
const TypeId& type_id = GetTypeId(mid);
if (string_idx > type_id.descriptor_idx_) {
lo = mid + 1;
@@ -475,10 +517,10 @@ const DexFile::TypeId* DexFile::FindTypeId(uint32_t string_idx) const {
const DexFile::ProtoId* DexFile::FindProtoId(uint16_t return_type_idx,
const std::vector<uint16_t>& signature_type_idxs) const {
- uint32_t lo = 0;
- uint32_t hi = NumProtoIds() - 1;
+ int32_t lo = 0;
+ int32_t hi = NumProtoIds() - 1;
while (hi >= lo) {
- uint32_t mid = (hi + lo) / 2;
+ int32_t mid = (hi + lo) / 2;
const DexFile::ProtoId& proto = GetProtoId(mid);
int compare = return_type_idx - proto.return_type_idx_;
if (compare == 0) {
@@ -544,7 +586,7 @@ bool DexFile::CreateTypeList(uint16_t* return_type_idx, std::vector<uint16_t>* p
descriptor += c;
} while (c != ';');
}
- const DexFile::StringId* string_id = FindStringId(descriptor);
+ const DexFile::StringId* string_id = FindStringId(descriptor.c_str());
if (string_id == NULL) {
return false;
}
diff --git a/src/dex_file.h b/src/dex_file.h
index 6e34b5737f..e09270e018 100644
--- a/src/dex_file.h
+++ b/src/dex_file.h
@@ -21,6 +21,7 @@
#include <vector>
#include "base/logging.h"
+#include "base/mutex.h"
#include "base/stringpiece.h"
#include "globals.h"
#include "invoke_type.h"
@@ -384,6 +385,10 @@ class DexFile {
return *header_;
}
+ Mutex& GetModificationLock() {
+ return modification_lock;
+ }
+
// Decode the dex magic version
uint32_t GetVersion() const;
@@ -436,8 +441,11 @@ class DexFile {
return StringDataAndLengthByIdx(idx, &unicode_length);
}
- // Looks up a string id for a given string
- const StringId* FindStringId(const std::string& string) const;
+ // Looks up a string id for a given modified utf8 string.
+ const StringId* FindStringId(const char* string) const;
+
+ // Looks up a string id for a given utf16 string.
+ const StringId* FindStringId(const uint16_t* string) const;
// Returns the number of type identifiers in the .dex file.
size_t NumTypeIds() const {
@@ -795,6 +803,12 @@ class DexFile {
int GetPermissions() const;
+ bool IsReadOnly() const;
+
+ bool EnableWrite(uint8_t* addr, size_t size) const;
+
+ bool DisableWrite(uint8_t* addr, size_t size) const;
+
private:
// Opens a .dex file
static const DexFile* OpenFile(const std::string& filename,
@@ -827,6 +841,7 @@ class DexFile {
location_checksum_(location_checksum),
mem_map_(mem_map),
dex_object_(NULL),
+ modification_lock("DEX modification lock"),
header_(0),
string_ids_(0),
type_ids_(0),
@@ -887,6 +902,11 @@ class DexFile {
// TODO: this is mutable as it shouldn't be here. We should move it to the dex cache or similar.
mutable jobject dex_object_;
+ // The DEX-to-DEX compiler uses this lock to ensure thread safety when
+ // enabling write access to a read-only DEX file.
+ // TODO: move to Locks::dex_file_modification_lock.
+ Mutex modification_lock;
+
// Points to the header section.
const Header* header_;
@@ -974,7 +994,7 @@ class ClassDataItemIterator {
bool HasNext() const {
return pos_ < EndOfVirtualMethodsPos();
}
- void Next() {
+ inline void Next() {
pos_++;
if (pos_ < EndOfStaticFieldsPos()) {
last_idx_ = GetMemberIndex();
diff --git a/src/dex_file_verifier.cc b/src/dex_file_verifier.cc
index b1efcaadbd..6df4411565 100644
--- a/src/dex_file_verifier.cc
+++ b/src/dex_file_verifier.cc
@@ -369,10 +369,12 @@ bool DexFileVerifier::CheckClassDataItemMethod(uint32_t idx, uint32_t access_fla
}
if (expect_code && code_offset == 0) {
- LOG(ERROR) << StringPrintf("Unexpected zero value for class_data_item method code_off with access flags %x", access_flags);
+ LOG(ERROR)<< StringPrintf("Unexpected zero value for class_data_item method code_off"
+ " with access flags %x", access_flags);
return false;
} else if (!expect_code && code_offset != 0) {
- LOG(ERROR) << StringPrintf("Unexpected non-zero value %x for class_data_item method code_off with access flags %x", code_offset, access_flags);
+ LOG(ERROR) << StringPrintf("Unexpected non-zero value %x for class_data_item method code_off"
+ " with access flags %x", code_offset, access_flags);
return false;
}
@@ -544,7 +546,8 @@ bool DexFileVerifier::CheckEncodedAnnotation() {
}
if (last_idx >= idx && i != 0) {
- LOG(ERROR) << StringPrintf("Out-of-order annotation_element name_idx: %x then %x", last_idx, idx);
+ LOG(ERROR) << StringPrintf("Out-of-order annotation_element name_idx: %x then %x",
+ last_idx, idx);
return false;
}
@@ -651,7 +654,8 @@ bool DexFileVerifier::CheckIntraCodeItem() {
uint32_t last_addr = 0;
while (try_items_size--) {
if (try_items->start_addr_ < last_addr) {
- LOG(ERROR) << StringPrintf("Out-of_order try_item with start_addr: %x", try_items->start_addr_);
+ LOG(ERROR) << StringPrintf("Out-of_order try_item with start_addr: %x",
+ try_items->start_addr_);
return false;
}
@@ -933,7 +937,8 @@ bool DexFileVerifier::CheckIntraAnnotationsDirectoryItem() {
last_idx = 0;
for (uint32_t i = 0; i < method_count; i++) {
if (last_idx >= method_item->method_idx_ && i != 0) {
- LOG(ERROR) << StringPrintf("Out-of-order method_idx for annotation: %x then %x", last_idx, method_item->method_idx_);
+ LOG(ERROR) << StringPrintf("Out-of-order method_idx for annotation: %x then %x",
+ last_idx, method_item->method_idx_);
return false;
}
last_idx = method_item->method_idx_;
@@ -944,14 +949,16 @@ bool DexFileVerifier::CheckIntraAnnotationsDirectoryItem() {
const DexFile::ParameterAnnotationsItem* parameter_item =
reinterpret_cast<const DexFile::ParameterAnnotationsItem*>(method_item);
uint32_t parameter_count = item->parameters_size_;
- if (!CheckListSize(parameter_item, parameter_count, sizeof(DexFile::ParameterAnnotationsItem), "parameter_annotations list")) {
+ if (!CheckListSize(parameter_item, parameter_count, sizeof(DexFile::ParameterAnnotationsItem),
+ "parameter_annotations list")) {
return false;
}
last_idx = 0;
for (uint32_t i = 0; i < parameter_count; i++) {
if (last_idx >= parameter_item->method_idx_ && i != 0) {
- LOG(ERROR) << StringPrintf("Out-of-order method_idx for annotation: %x then %x", last_idx, parameter_item->method_idx_);
+ LOG(ERROR) << StringPrintf("Out-of-order method_idx for annotation: %x then %x",
+ last_idx, parameter_item->method_idx_);
return false;
}
last_idx = parameter_item->method_idx_;
@@ -1051,7 +1058,8 @@ bool DexFileVerifier::CheckIntraSectionIterate(uint32_t offset, uint32_t count,
uint32_t count = list->size_;
if (!CheckPointerRange(list, list + 1, "annotation_set_ref_list") ||
- !CheckListSize(item, count, sizeof(DexFile::AnnotationSetRefItem), "annotation_set_ref_list size")) {
+ !CheckListSize(item, count, sizeof(DexFile::AnnotationSetRefItem),
+ "annotation_set_ref_list size")) {
return false;
}
ptr_ = reinterpret_cast<const byte*>(item + count);
@@ -1257,7 +1265,8 @@ bool DexFileVerifier::CheckIntraSection() {
return false;
}
if (section_offset != header_->map_off_) {
- LOG(ERROR) << StringPrintf("Map not at header-defined offset: %x, expected %x", section_offset, header_->map_off_);
+ LOG(ERROR) << StringPrintf("Map not at header-defined offset: %x, expected %x",
+ section_offset, header_->map_off_);
return false;
}
ptr_ += sizeof(uint32_t) + (map->size_ * sizeof(DexFile::MapItem));
@@ -1297,7 +1306,8 @@ bool DexFileVerifier::CheckOffsetToTypeMap(uint32_t offset, uint16_t type) {
return false;
}
if (it->second != type) {
- LOG(ERROR) << StringPrintf("Unexpected data map entry @ %x; expected %x, found %x", offset, type, it->second);
+ LOG(ERROR) << StringPrintf("Unexpected data map entry @ %x; expected %x, found %x",
+ offset, type, it->second);
return false;
}
return true;
@@ -1380,7 +1390,8 @@ bool DexFileVerifier::CheckInterTypeIdItem() {
if (previous_item_ != NULL) {
const DexFile::TypeId* prev_item = reinterpret_cast<const DexFile::TypeId*>(previous_item_);
if (prev_item->descriptor_idx_ >= item->descriptor_idx_) {
- LOG(ERROR) << StringPrintf("Out-of-order type_ids: %x then %x", prev_item->descriptor_idx_, item->descriptor_idx_);
+ LOG(ERROR) << StringPrintf("Out-of-order type_ids: %x then %x",
+ prev_item->descriptor_idx_, item->descriptor_idx_);
return false;
}
}
@@ -1757,7 +1768,8 @@ bool DexFileVerifier::CheckInterAnnotationsDirectoryItem() {
LOG(ERROR) << "Mismatched defining class for parameter_annotation";
return false;
}
- if (!CheckOffsetToTypeMap(parameter_item->annotations_off_, DexFile::kDexTypeAnnotationSetRefList)) {
+ if (!CheckOffsetToTypeMap(parameter_item->annotations_off_,
+ DexFile::kDexTypeAnnotationSetRefList)) {
return false;
}
parameter_item++;
diff --git a/src/dex_instruction-inl.h b/src/dex_instruction-inl.h
index 99dab121cf..b426e66a1c 100644
--- a/src/dex_instruction-inl.h
+++ b/src/dex_instruction-inl.h
@@ -21,13 +21,6 @@
namespace art {
-inline const Instruction* Instruction::Next_51l() const {
- DCHECK_EQ(FormatOf(Opcode()), k51l);
- size_t current_size_in_bytes = 5 * sizeof(uint16_t);
- const uint8_t* ptr = reinterpret_cast<const uint8_t*>(this);
- return reinterpret_cast<const Instruction*>(ptr + current_size_in_bytes);
-}
-
//------------------------------------------------------------------------------
// VRegA
//------------------------------------------------------------------------------
@@ -36,6 +29,11 @@ inline int8_t Instruction::VRegA_10t() const {
return static_cast<int8_t>(InstAA());
}
+inline uint8_t Instruction::VRegA_10x() const {
+ DCHECK_EQ(FormatOf(Opcode()), k10x);
+ return InstAA();
+}
+
inline uint4_t Instruction::VRegA_11n() const {
DCHECK_EQ(FormatOf(Opcode()), k11n);
return InstA();
diff --git a/src/dex_instruction.cc b/src/dex_instruction.cc
index 1b7d3bb3c4..c5901aa34b 100644
--- a/src/dex_instruction.cc
+++ b/src/dex_instruction.cc
@@ -82,6 +82,68 @@ static inline uint32_t fetch_uint32_impl(uint32_t offset, const uint16_t* insns)
return insns[offset] | ((uint32_t) insns[offset+1] << 16);
}
+int32_t Instruction::VRegC() const {
+ switch (FormatOf(Opcode())) {
+ case k22b: return VRegC_22b();
+ case k22c: return VRegC_22c();
+ case k22s: return VRegC_22s();
+ case k22t: return VRegC_22t();
+ case k23x: return VRegC_23x();
+ case k35c: return VRegC_35c();
+ case k3rc: return VRegC_3rc();
+ default: LOG(FATAL) << "Tried to access vC of instruction " << Name() <<
+ " which has no C operand.";
+ }
+ return 0;
+}
+
+int32_t Instruction::VRegB() const {
+ switch (FormatOf(Opcode())) {
+ case k11n: return VRegB_11n();
+ case k12x: return VRegB_12x();
+ case k21c: return VRegB_21c();
+ case k21h: return VRegB_21h();
+ case k21t: return VRegB_21t();
+ case k22b: return VRegB_22b();
+ case k22c: return VRegB_22c();
+ case k22s: return VRegB_22s();
+ case k22t: return VRegB_22t();
+ case k22x: return VRegB_22x();
+ case k31c: return VRegB_31c();
+ case k31i: return VRegB_31i();
+ case k31t: return VRegB_31t();
+ case k32x: return VRegB_32x();
+ case k35c: return VRegB_35c();
+ case k3rc: return VRegB_3rc();
+ case k51l: return VRegB_51l();
+ default: LOG(FATAL) << "Tried to access vB of instruction " << Name() <<
+ " which has no B operand.";
+ }
+ return 0;
+}
+
+int32_t Instruction::GetTargetOffset() const {
+ switch (FormatOf(Opcode())) {
+ // Cases for conditional branches follow.
+ case k22t: return VRegC_22t();
+ case k21t: return VRegB_21t();
+ // Cases for unconditional branches follow.
+ case k10t: return VRegA_10t();
+ case k20t: return VRegA_20t();
+ case k30t: return VRegA_30t();
+ default: LOG(FATAL) << "Tried to access the branch offset of an instruction " << Name() <<
+ " which does not have a target operand.";
+ }
+ return 0;
+}
+
+bool Instruction::CanFlowThrough() const {
+ const uint16_t* insns = reinterpret_cast<const uint16_t*>(this);
+ uint16_t insn = *insns;
+ Code opcode = static_cast<Code>(insn & 0xFF);
+ return FlagsOf(opcode) & Instruction::kContinue;
+}
+
void Instruction::Decode(uint32_t &vA, uint32_t &vB, uint64_t &vB_wide, uint32_t &vC, uint32_t arg[]) const {
const uint16_t* insns = reinterpret_cast<const uint16_t*>(this);
uint16_t insn = *insns;
@@ -299,7 +361,7 @@ std::string Instruction::DumpString(const DexFile* file) const {
case NEW_INSTANCE:
if (file != NULL) {
uint32_t type_idx = VRegB_21c();
- os << opcode << " v" << VRegA_21c() << ", " << PrettyType(type_idx, *file)
+ os << opcode << " v" << static_cast<int>(VRegA_21c()) << ", " << PrettyType(type_idx, *file)
<< " // type@" << type_idx;
break;
} // else fall-through
@@ -312,7 +374,7 @@ std::string Instruction::DumpString(const DexFile* file) const {
case SGET_SHORT:
if (file != NULL) {
uint32_t field_idx = VRegB_21c();
- os << opcode << " v" << VRegA_21c() << ", " << PrettyField(field_idx, *file, true)
+ os << opcode << " v" << static_cast<int>(VRegA_21c()) << ", " << PrettyField(field_idx, *file, true)
<< " // field@" << field_idx;
break;
} // else fall-through
@@ -325,7 +387,7 @@ std::string Instruction::DumpString(const DexFile* file) const {
case SPUT_SHORT:
if (file != NULL) {
uint32_t field_idx = VRegB_21c();
- os << opcode << " v" << VRegA_21c() << ", " << PrettyField(field_idx, *file, true)
+ os << opcode << " v" << static_cast<int>(VRegA_21c()) << ", " << PrettyField(field_idx, *file, true)
<< " // field@" << field_idx;
break;
} // else fall-through
@@ -350,10 +412,18 @@ std::string Instruction::DumpString(const DexFile* file) const {
case IGET_SHORT:
if (file != NULL) {
uint32_t field_idx = VRegC_22c();
- os << opcode << " v" << VRegA_22c() << ", v" << VRegB_22c() << ", "
+ os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", "
<< PrettyField(field_idx, *file, true) << " // field@" << field_idx;
break;
} // else fall-through
+ case IGET_QUICK:
+ case IGET_OBJECT_QUICK:
+ if (file != NULL) {
+ uint32_t field_idx = VRegC_22c();
+ os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", "
+ << "// offset@" << field_idx;
+ break;
+ } // else fall-through
case IPUT:
case IPUT_WIDE:
case IPUT_OBJECT:
@@ -363,21 +433,29 @@ std::string Instruction::DumpString(const DexFile* file) const {
case IPUT_SHORT:
if (file != NULL) {
uint32_t field_idx = VRegC_22c();
- os << opcode << " v" << VRegA_22c() << ", v" << VRegB_22c() << ", "
+ os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", "
<< PrettyField(field_idx, *file, true) << " // field@" << field_idx;
break;
} // else fall-through
+ case IPUT_QUICK:
+ case IPUT_OBJECT_QUICK:
+ if (file != NULL) {
+ uint32_t field_idx = VRegC_22c();
+ os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", "
+ << "// offset@" << field_idx;
+ break;
+ } // else fall-through
case INSTANCE_OF:
if (file != NULL) {
uint32_t type_idx = VRegC_22c();
- os << opcode << " v" << VRegA_22c() << ", v" << VRegB_22c() << ", "
+ os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", "
<< PrettyType(type_idx, *file) << " // type@" << type_idx;
break;
}
case NEW_ARRAY:
if (file != NULL) {
uint32_t type_idx = VRegC_22c();
- os << opcode << " v" << VRegA_22c() << ", v" << VRegB_22c() << ", "
+ os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", "
<< PrettyType(type_idx, *file) << " // type@" << type_idx;
break;
} // else fall-through
@@ -413,6 +491,19 @@ std::string Instruction::DumpString(const DexFile* file) const {
os << "}, " << PrettyMethod(method_idx, *file) << " // method@" << method_idx;
break;
} // else fall-through
+ case INVOKE_VIRTUAL_QUICK:
+ if (file != NULL) {
+ os << opcode << " {";
+ uint32_t method_idx = VRegB_35c();
+ for (size_t i = 0; i < VRegA_35c(); ++i) {
+ if (i != 0) {
+ os << ", ";
+ }
+ os << "v" << arg[i];
+ }
+ os << "}, // vtable@" << method_idx;
+ break;
+ } // else fall-through
default:
os << opcode << " {v" << arg[0] << ", v" << arg[1] << ", v" << arg[2]
<< ", v" << arg[3] << ", v" << arg[4] << "}, thing@" << VRegB_35c();
@@ -433,6 +524,13 @@ std::string Instruction::DumpString(const DexFile* file) const {
<< PrettyMethod(method_idx, *file) << " // method@" << method_idx;
break;
} // else fall-through
+ case INVOKE_VIRTUAL_RANGE_QUICK:
+ if (file != NULL) {
+ uint32_t method_idx = VRegB_3rc();
+ os << StringPrintf("%s, {v%d .. v%d}, ", opcode, VRegC_3rc(), (VRegC_3rc() + VRegA_3rc() - 1))
+ << "// vtable@" << method_idx;
+ break;
+ } // else fall-through
default:
os << StringPrintf("%s, {v%d .. v%d}, thing@%d", opcode, VRegC_3rc(),
(VRegC_3rc() + VRegA_3rc() - 1), VRegB_3rc());
diff --git a/src/dex_instruction.h b/src/dex_instruction.h
index 218acb6fe1..602667aa4e 100644
--- a/src/dex_instruction.h
+++ b/src/dex_instruction.h
@@ -46,6 +46,7 @@ class Instruction {
const uint16_t case_count;
const int32_t first_key;
const int32_t targets[];
+
private:
DISALLOW_COPY_AND_ASSIGN(PackedSwitchPayload);
};
@@ -73,6 +74,7 @@ class Instruction {
const uint16_t element_width;
const uint32_t element_count;
const uint8_t data[];
+
private:
DISALLOW_COPY_AND_ASSIGN(ArrayDataPayload);
};
@@ -162,39 +164,45 @@ class Instruction {
}
}
+ // Reads an instruction out of the stream at the specified address.
+ static const Instruction* At(const uint16_t* code) {
+ DCHECK(code != NULL);
+ return reinterpret_cast<const Instruction*>(code);
+ }
+
+ // Reads an instruction out of the stream from the current address plus an offset.
+ const Instruction* RelativeAt(int32_t offset) const {
+ return At(reinterpret_cast<const uint16_t*>(this) + offset);
+ }
+
// Returns a pointer to the next instruction in the stream.
const Instruction* Next() const {
- size_t current_size_in_bytes = SizeInCodeUnits() * sizeof(uint16_t);
- const uint8_t* ptr = reinterpret_cast<const uint8_t*>(this);
- return reinterpret_cast<const Instruction*>(ptr + current_size_in_bytes);
+ return RelativeAt(SizeInCodeUnits());
}
// Returns a pointer to the instruction after this 1xx instruction in the stream.
const Instruction* Next_1xx() const {
DCHECK(FormatOf(Opcode()) >= k10x && FormatOf(Opcode()) <= k10t);
- size_t current_size_in_bytes = 1 * sizeof(uint16_t);
- const uint8_t* ptr = reinterpret_cast<const uint8_t*>(this);
- return reinterpret_cast<const Instruction*>(ptr + current_size_in_bytes);
+ return RelativeAt(1);
}
// Returns a pointer to the instruction after this 2xx instruction in the stream.
const Instruction* Next_2xx() const {
DCHECK(FormatOf(Opcode()) >= k20t && FormatOf(Opcode()) <= k22c);
- size_t current_size_in_bytes = 2 * sizeof(uint16_t);
- const uint8_t* ptr = reinterpret_cast<const uint8_t*>(this);
- return reinterpret_cast<const Instruction*>(ptr + current_size_in_bytes);
+ return RelativeAt(2);
}
// Returns a pointer to the instruction after this 3xx instruction in the stream.
const Instruction* Next_3xx() const {
DCHECK(FormatOf(Opcode()) >= k32x && FormatOf(Opcode()) <= k3rc);
- size_t current_size_in_bytes = 3 * sizeof(uint16_t);
- const uint8_t* ptr = reinterpret_cast<const uint8_t*>(this);
- return reinterpret_cast<const Instruction*>(ptr + current_size_in_bytes);
+ return RelativeAt(3);
}
// Returns a pointer to the instruction after this 51l instruction in the stream.
- const Instruction* Next_51l() const;
+ const Instruction* Next_51l() const {
+ DCHECK(FormatOf(Opcode()) == k51l);
+ return RelativeAt(5);
+ }
// Returns the name of this instruction's opcode.
const char* Name() const {
@@ -208,6 +216,7 @@ class Instruction {
// VRegA
int8_t VRegA_10t() const;
+ uint8_t VRegA_10x() const;
uint4_t VRegA_11n() const;
uint8_t VRegA_11x() const;
uint4_t VRegA_12x() const;
@@ -232,6 +241,7 @@ class Instruction {
uint8_t VRegA_51l() const;
// VRegB
+ int32_t VRegB() const;
int4_t VRegB_11n() const;
uint4_t VRegB_12x() const;
uint16_t VRegB_21c() const;
@@ -250,9 +260,10 @@ class Instruction {
uint16_t VRegB_32x() const;
uint16_t VRegB_35c() const;
uint16_t VRegB_3rc() const;
- uint64_t VRegB_51l() const; // vB_wide
+ uint64_t VRegB_51l() const; // vB_wide
// VRegC
+ int32_t VRegC() const;
int8_t VRegC_22b() const;
uint16_t VRegC_22c() const;
int16_t VRegC_22s() const;
@@ -271,10 +282,28 @@ class Instruction {
return static_cast<Code>(opcode);
}
- // Reads an instruction out of the stream at the specified address.
- static const Instruction* At(const uint16_t* code) {
- CHECK(code != NULL);
- return reinterpret_cast<const Instruction*>(code);
+ void SetOpcode(Code opcode) {
+ DCHECK_LT(static_cast<uint16_t>(opcode), 256u);
+ uint16_t* insns = reinterpret_cast<uint16_t*>(this);
+ insns[0] = (insns[0] & 0xff00) | static_cast<uint16_t>(opcode);
+ }
+
+ void SetVRegB_3rc(uint16_t val) {
+ DCHECK(FormatOf(Opcode()) == k3rc);
+ uint16_t* insns = reinterpret_cast<uint16_t*>(this);
+ insns[1] = val;
+ }
+
+ void SetVRegB_35c(uint16_t val) {
+ DCHECK(FormatOf(Opcode()) == k35c);
+ uint16_t* insns = reinterpret_cast<uint16_t*>(this);
+ insns[1] = val;
+ }
+
+ void SetVRegC_22c(uint16_t val) {
+ DCHECK(FormatOf(Opcode()) == k22c);
+ uint16_t* insns = reinterpret_cast<uint16_t*>(this);
+ insns[1] = val;
}
// Returns the format of the given opcode.
@@ -297,6 +326,12 @@ class Instruction {
return (kInstructionFlags[Opcode()] & kUnconditional) != 0;
}
+ // Returns the branch offset if this instruction is a branch.
+ int32_t GetTargetOffset() const;
+
+ // Returns true if the instruction allows control flow to go to the following instruction.
+ bool CanFlowThrough() const;
+
// Returns true if this instruction is a switch.
bool IsSwitch() const {
return (kInstructionFlags[Opcode()] & kSwitch) != 0;
diff --git a/src/dex_instruction_list.h b/src/dex_instruction_list.h
index 3083d224e9..9daec61ba5 100644
--- a/src/dex_instruction_list.h
+++ b/src/dex_instruction_list.h
@@ -242,14 +242,14 @@
V(0xE0, SHL_INT_LIT8, "shl-int/lit8", k22b, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
V(0xE1, SHR_INT_LIT8, "shr-int/lit8", k22b, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
V(0xE2, USHR_INT_LIT8, "ushr-int/lit8", k22b, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
- V(0xE3, UNUSED_E3, "unused-e3", k10x, false, kUnknown, 0, kVerifyError) \
- V(0xE4, UNUSED_E4, "unused-e4", k10x, false, kUnknown, 0, kVerifyError) \
- V(0xE5, UNUSED_E5, "unused-e5", k10x, false, kUnknown, 0, kVerifyError) \
- V(0xE6, UNUSED_E6, "unused-e6", k10x, false, kUnknown, 0, kVerifyError) \
- V(0xE7, UNUSED_E7, "unused-e7", k10x, false, kUnknown, 0, kVerifyError) \
- V(0xE8, UNUSED_E8, "unused-e8", k10x, false, kUnknown, 0, kVerifyError) \
- V(0xE9, UNUSED_E9, "unused-e9", k10x, false, kUnknown, 0, kVerifyError) \
- V(0xEA, UNUSED_EA, "unused-ea", k10x, false, kUnknown, 0, kVerifyError) \
+ V(0xE3, IGET_QUICK, "iget-quick", k22c, true, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegB) \
+ V(0xE4, IGET_WIDE_QUICK, "iget-wide-quick", k22c, true, kFieldRef, kContinue | kThrow, kVerifyRegAWide | kVerifyRegB) \
+ V(0xE5, IGET_OBJECT_QUICK, "iget-object-quick", k22c, true, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegB) \
+ V(0xE6, IPUT_QUICK, "iput-quick", k22c, false, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegB) \
+ V(0xE7, IPUT_WIDE_QUICK, "iput-wide-quick", k22c, false, kFieldRef, kContinue | kThrow, kVerifyRegAWide | kVerifyRegB) \
+ V(0xE8, IPUT_OBJECT_QUICK, "iput-object-quick", k22c, false, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegB) \
+ V(0xE9, INVOKE_VIRTUAL_QUICK, "invoke-virtual-quick", k35c, false, kMethodRef, kContinue | kThrow | kInvoke, kVerifyVarArg) \
+ V(0xEA, INVOKE_VIRTUAL_RANGE_QUICK, "invoke-virtual/range-quick", k3rc, false, kMethodRef, kContinue | kThrow | kInvoke, kVerifyVarArgRange) \
V(0xEB, UNUSED_EB, "unused-eb", k10x, false, kUnknown, 0, kVerifyError) \
V(0xEC, UNUSED_EC, "unused-ec", k10x, false, kUnknown, 0, kVerifyError) \
V(0xED, UNUSED_ED, "unused-ed", k10x, false, kUnknown, 0, kVerifyError) \
diff --git a/src/disassembler_arm.cc b/src/disassembler_arm.cc
index 7e75600b19..172bef84d6 100644
--- a/src/disassembler_arm.cc
+++ b/src/disassembler_arm.cc
@@ -1223,7 +1223,7 @@ size_t DisassemblerArm::DumpThumb16(std::ostream& os, const uint8_t* instr_ptr)
args << Rt << ", [" << Rn << ", #" << imm5 << "]";
}
} else if (opcode1 >= 0x34 && opcode1 <= 0x37) { // 1101xx
- uint32_t imm8 = instr & 0xFF;
+ int8_t imm8 = instr & 0xFF;
uint32_t cond = (instr >> 8) & 0xF;
opcode << "b";
DumpCond(opcode, cond);
@@ -1260,7 +1260,7 @@ size_t DisassemblerArm::DumpThumb16(std::ostream& os, const uint8_t* instr_ptr)
uint16_t imm5 = (instr >> 3) & 0x1F;
ThumbRegister Rn(instr, 0);
opcode << (op != 0 ? "cbnz" : "cbz");
- uint32_t imm32 = (i << 7) | (imm5 << 1);
+ uint32_t imm32 = (i << 6) | (imm5 << 1);
args << Rn << ", ";
DumpBranchTarget(args, instr_ptr + 4, imm32);
break;
diff --git a/src/gc/atomic_stack.h b/src/gc/accounting/atomic_stack.h
index 0197bce992..4e1c253bdf 100644
--- a/src/gc/atomic_stack.h
+++ b/src/gc/accounting/atomic_stack.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ART_SRC_ATOMIC_STACK_H_
-#define ART_SRC_ATOMIC_STACK_H_
+#ifndef ART_SRC_GC_ACCOUNTING_ATOMIC_STACK_H_
+#define ART_SRC_GC_ACCOUNTING_ATOMIC_STACK_H_
#include <string>
@@ -27,6 +27,8 @@
#include "utils.h"
namespace art {
+namespace gc {
+namespace accounting {
template <typename T>
class AtomicStack {
@@ -38,15 +40,14 @@ class AtomicStack {
return mark_stack.release();
}
- ~AtomicStack(){
-
- }
+ ~AtomicStack() {}
void Reset() {
DCHECK(mem_map_.get() != NULL);
DCHECK(begin_ != NULL);
front_index_ = 0;
back_index_ = 0;
+ is_sorted_ = true;
int result = madvise(begin_, sizeof(T) * capacity_, MADV_DONTNEED);
if (result == -1) {
PLOG(WARNING) << "madvise failed";
@@ -58,6 +59,7 @@ class AtomicStack {
// Returns false if we overflowed the stack.
bool AtomicPushBack(const T& value) {
int32_t index;
+ is_sorted_ = false;
do {
index = back_index_;
if (UNLIKELY(static_cast<size_t>(index) >= capacity_)) {
@@ -70,6 +72,7 @@ class AtomicStack {
}
void PushBack(const T& value) {
+ is_sorted_ = false;
int32_t index = back_index_;
DCHECK_LT(static_cast<size_t>(index), capacity_);
back_index_ = index + 1;
@@ -100,11 +103,11 @@ class AtomicStack {
return back_index_ - front_index_;
}
- T* Begin() {
+ T* Begin() const {
return const_cast<mirror::Object**>(begin_ + front_index_);
}
- T* End() {
+ T* End() const {
return const_cast<mirror::Object**>(begin_ + back_index_);
}
@@ -118,14 +121,33 @@ class AtomicStack {
Init();
}
+ void Sort() {
+ if (!is_sorted_) {
+ int32_t start_back_index = back_index_.get();
+ int32_t start_front_index = front_index_.get();
+ is_sorted_ = true;
+ std::sort(Begin(), End());
+ CHECK_EQ(start_back_index, back_index_.get());
+ CHECK_EQ(start_front_index, front_index_.get());
+ }
+ }
+
+ bool Contains(const T& value) const {
+ if (is_sorted_) {
+ return std::binary_search(Begin(), End(), value);
+ } else {
+ return std::find(Begin(), End(), value) != End();
+ }
+ }
+
private:
AtomicStack(const std::string& name, const size_t capacity)
: name_(name),
back_index_(0),
front_index_(0),
begin_(NULL),
- capacity_(capacity) {
-
+ capacity_(capacity),
+ is_sorted_(true) {
}
// Size in number of elements.
@@ -156,11 +178,15 @@ class AtomicStack {
// Maximum number of elements.
size_t capacity_;
+ bool is_sorted_;
+
DISALLOW_COPY_AND_ASSIGN(AtomicStack);
};
typedef AtomicStack<mirror::Object*> ObjectStack;
+} // namespace accounting
+} // namespace gc
} // namespace art
-#endif // ART_SRC_MARK_STACK_H_
+#endif // ART_SRC_GC_ACCOUNTING_ATOMIC_STACK_H_
diff --git a/src/gc/card_table-inl.h b/src/gc/accounting/card_table-inl.h
index 13590b70a9..1e7529084a 100644
--- a/src/gc/card_table-inl.h
+++ b/src/gc/accounting/card_table-inl.h
@@ -24,6 +24,8 @@
#include "utils.h"
namespace art {
+namespace gc {
+namespace accounting {
static inline bool byte_cas(byte old_value, byte new_value, byte* address) {
// Little endian means most significant byte is on the left.
@@ -204,6 +206,8 @@ inline void CardTable::CheckCardValid(byte* card) const {
<< " end: " << reinterpret_cast<void*>(mem_map_->End());
}
+} // namespace accounting
+} // namespace gc
} // namespace art
#endif // ART_SRC_GC_CARDTABLE_INL_H_
diff --git a/src/gc/card_table.cc b/src/gc/accounting/card_table.cc
index 57824e90db..4f2ae26c37 100644
--- a/src/gc/card_table.cc
+++ b/src/gc/accounting/card_table.cc
@@ -17,14 +17,17 @@
#include "card_table.h"
#include "base/logging.h"
-#include "gc/card_table-inl.h"
-#include "heap.h"
+#include "card_table-inl.h"
+#include "gc/heap.h"
+#include "gc/space/space.h"
#include "heap_bitmap.h"
#include "runtime.h"
-#include "space.h"
#include "utils.h"
namespace art {
+namespace gc {
+namespace accounting {
+
/*
* Maintain a card table from the write barrier. All writes of
* non-NULL values to heap addresses should go through an entry in
@@ -82,7 +85,7 @@ CardTable::CardTable(MemMap* mem_map, byte* biased_begin, size_t offset)
byte* __attribute__((unused)) end = mem_map_->End();
}
-void CardTable::ClearSpaceCards(ContinuousSpace* space) {
+void CardTable::ClearSpaceCards(space::ContinuousSpace* space) {
// TODO: clear just the range of the table that has been modified
byte* card_start = CardFromAddr(space->Begin());
byte* card_end = CardFromAddr(space->End()); // Make sure to round up.
@@ -116,4 +119,6 @@ void CardTable::VerifyCardTable() {
UNIMPLEMENTED(WARNING) << "Card table verification";
}
+} // namespace accounting
+} // namespace gc
} // namespace art
diff --git a/src/gc/card_table.h b/src/gc/accounting/card_table.h
index 842fcc3aa2..cf85d15448 100644
--- a/src/gc/card_table.h
+++ b/src/gc/accounting/card_table.h
@@ -23,11 +23,21 @@
#include "UniquePtr.h"
namespace art {
+
namespace mirror {
-class Object;
+ class Object;
} // namespace mirror
+
+namespace gc {
+
+namespace space {
+ class ContinuousSpace;
+} // namespace space
+
class Heap;
-class ContinuousSpace;
+
+namespace accounting {
+
class SpaceBitmap;
// Maintain a card table from the the write barrier. All writes of
@@ -105,7 +115,7 @@ class CardTable {
void ClearCardTable();
// Resets all of the bytes in the card table which do not map to the image space.
- void ClearSpaceCards(ContinuousSpace* space);
+ void ClearSpaceCards(space::ContinuousSpace* space);
// Returns the first address in the heap which maps to this card.
void* AddrFromCard(const byte *card_addr) const;
@@ -139,5 +149,8 @@ class CardTable {
const size_t offset_;
};
+} // namespace accounting
+} // namespace gc
} // namespace art
+
#endif // ART_SRC_GC_CARDTABLE_H_
diff --git a/src/gc/heap_bitmap-inl.h b/src/gc/accounting/heap_bitmap-inl.h
index 281118359b..8e3123b974 100644
--- a/src/gc/heap_bitmap-inl.h
+++ b/src/gc/accounting/heap_bitmap-inl.h
@@ -14,23 +14,37 @@
* limitations under the License.
*/
-#ifndef ART_SRC_GC_HEAP_BITMAP_INL_H_
-#define ART_SRC_GC_HEAP_BITMAP_INL_H_
+#ifndef ART_SRC_GC_ACCOUNTING_HEAP_BITMAP_INL_H_
+#define ART_SRC_GC_ACCOUNTING_HEAP_BITMAP_INL_H_
#include "heap_bitmap.h"
namespace art {
+namespace gc {
+namespace accounting {
template <typename Visitor>
inline void HeapBitmap::Visit(const Visitor& visitor) {
// TODO: C++0x auto
- for (Bitmaps::iterator it = bitmaps_.begin(); it != bitmaps_.end(); ++it) {
+ typedef std::vector<SpaceBitmap*>::iterator It;
+ for (It it = continuous_space_bitmaps_.begin(), end = continuous_space_bitmaps_.end();
+ it != end; ++it) {
SpaceBitmap* bitmap = *it;
bitmap->VisitMarkedRange(bitmap->HeapBegin(), bitmap->HeapLimit(), visitor, VoidFunctor());
}
- large_objects_->Visit(visitor);
+ // TODO: C++0x auto
+ typedef std::vector<SpaceSetMap*>::iterator It2;
+ DCHECK(discontinuous_space_sets_.begin() != discontinuous_space_sets_.end());
+ for (It2 it = discontinuous_space_sets_.begin(), end = discontinuous_space_sets_.end();
+ it != end; ++it) {
+ SpaceSetMap* set = *it;
+ set->Visit(visitor);
+ }
+
}
+} // namespace accounting
+} // namespace gc
} // namespace art
-#endif // ART_SRC_GC_HEAP_BITMAP_INL_H_
+#endif // ART_SRC_GC_ACCOUNTING_HEAP_BITMAP_INL_H_
diff --git a/src/gc/accounting/heap_bitmap.cc b/src/gc/accounting/heap_bitmap.cc
new file mode 100644
index 0000000000..1bdc9783fa
--- /dev/null
+++ b/src/gc/accounting/heap_bitmap.cc
@@ -0,0 +1,92 @@
+/*
+ * 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 "heap_bitmap.h"
+
+#include "gc/space/space.h"
+
+namespace art {
+namespace gc {
+namespace accounting {
+
+void HeapBitmap::ReplaceBitmap(SpaceBitmap* old_bitmap, SpaceBitmap* new_bitmap) {
+ // TODO: C++0x auto
+ typedef std::vector<SpaceBitmap*>::iterator It;
+ for (It it = continuous_space_bitmaps_.begin(), end = continuous_space_bitmaps_.end();
+ it != end; ++it) {
+ if (*it == old_bitmap) {
+ *it = new_bitmap;
+ return;
+ }
+ }
+ LOG(FATAL) << "bitmap " << static_cast<const void*>(old_bitmap) << " not found";
+}
+
+void HeapBitmap::ReplaceObjectSet(SpaceSetMap* old_set, SpaceSetMap* new_set) {
+ // TODO: C++0x auto
+ typedef std::vector<SpaceSetMap*>::iterator It;
+ for (It it = discontinuous_space_sets_.begin(), end = discontinuous_space_sets_.end();
+ it != end; ++it) {
+ if (*it == old_set) {
+ *it = new_set;
+ return;
+ }
+ }
+ LOG(FATAL) << "object set " << static_cast<const void*>(old_set) << " not found";
+}
+
+void HeapBitmap::AddContinuousSpaceBitmap(accounting::SpaceBitmap* bitmap) {
+ DCHECK(bitmap != NULL);
+
+ // Check for interval overlap.
+ typedef std::vector<SpaceBitmap*>::iterator It;
+ for (It it = continuous_space_bitmaps_.begin(), end = continuous_space_bitmaps_.end();
+ it != end; ++it) {
+ SpaceBitmap* bitmap = *it;
+ SpaceBitmap* cur_bitmap = *it;
+ CHECK(bitmap->HeapBegin() < cur_bitmap->HeapLimit() &&
+ bitmap->HeapLimit() > cur_bitmap->HeapBegin())
+ << "Bitmap " << bitmap->Dump() << " overlaps with existing bitmap " << cur_bitmap->Dump();
+ }
+ continuous_space_bitmaps_.push_back(bitmap);
+}
+
+void HeapBitmap::AddDiscontinuousObjectSet(SpaceSetMap* set) {
+ DCHECK(set != NULL);
+ discontinuous_space_sets_.push_back(set);
+}
+
+void HeapBitmap::Walk(SpaceBitmap::Callback* callback, void* arg) {
+ // TODO: C++0x auto
+ typedef std::vector<SpaceBitmap*>::iterator It;
+ for (It it = continuous_space_bitmaps_.begin(), end = continuous_space_bitmaps_.end();
+ it != end; ++it) {
+ SpaceBitmap* bitmap = *it;
+ bitmap->Walk(callback, arg);
+ }
+ // TODO: C++0x auto
+ typedef std::vector<SpaceSetMap*>::iterator It2;
+ DCHECK(discontinuous_space_sets_.begin() != discontinuous_space_sets_.end());
+ for (It2 it = discontinuous_space_sets_.begin(), end = discontinuous_space_sets_.end();
+ it != end; ++it) {
+ SpaceSetMap* set = *it;
+ set->Walk(callback, arg);
+ }
+}
+
+} // namespace accounting
+} // namespace gc
+} // namespace art
diff --git a/src/gc/accounting/heap_bitmap.h b/src/gc/accounting/heap_bitmap.h
new file mode 100644
index 0000000000..5ff40c6426
--- /dev/null
+++ b/src/gc/accounting/heap_bitmap.h
@@ -0,0 +1,129 @@
+/*
+ * 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_GC_ACCOUNTING_HEAP_BITMAP_H_
+#define ART_SRC_GC_ACCOUNTING_HEAP_BITMAP_H_
+
+#include "base/logging.h"
+#include "locks.h"
+#include "space_bitmap.h"
+
+namespace art {
+namespace gc {
+
+class Heap;
+
+namespace accounting {
+
+class HeapBitmap {
+ public:
+ bool Test(const mirror::Object* obj) SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_) {
+ SpaceBitmap* bitmap = GetContinuousSpaceBitmap(obj);
+ if (LIKELY(bitmap != NULL)) {
+ return bitmap->Test(obj);
+ } else {
+ return GetDiscontinuousSpaceObjectSet(obj) != NULL;
+ }
+ }
+
+ void Clear(const mirror::Object* obj) EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_) {
+ SpaceBitmap* bitmap = GetContinuousSpaceBitmap(obj);
+ if (LIKELY(bitmap != NULL)) {
+ bitmap->Clear(obj);
+ } else {
+ SpaceSetMap* set = GetDiscontinuousSpaceObjectSet(obj);
+ DCHECK(set != NULL);
+ set->Clear(obj);
+ }
+ }
+
+ void Set(const mirror::Object* obj) EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_) {
+ SpaceBitmap* bitmap = GetContinuousSpaceBitmap(obj);
+ if (LIKELY(bitmap != NULL)) {
+ bitmap->Set(obj);
+ } else {
+ SpaceSetMap* set = GetDiscontinuousSpaceObjectSet(obj);
+ DCHECK(set != NULL);
+ set->Set(obj);
+ }
+ }
+
+ SpaceBitmap* GetContinuousSpaceBitmap(const mirror::Object* obj) {
+ // TODO: C++0x auto
+ typedef std::vector<SpaceBitmap*>::iterator It;
+ for (It it = continuous_space_bitmaps_.begin(), end = continuous_space_bitmaps_.end();
+ it != end; ++it) {
+ SpaceBitmap* bitmap = *it;
+ if (bitmap->HasAddress(obj)) {
+ return bitmap;
+ }
+ }
+ return NULL;
+ }
+
+ SpaceSetMap* GetDiscontinuousSpaceObjectSet(const mirror::Object* obj) {
+ // TODO: C++0x auto
+ typedef std::vector<SpaceSetMap*>::iterator It;
+ for (It it = discontinuous_space_sets_.begin(), end = discontinuous_space_sets_.end();
+ it != end; ++it) {
+ SpaceSetMap* set = *it;
+ if (set->Test(obj)) {
+ return set;
+ }
+ }
+ return NULL;
+ }
+
+ void Walk(SpaceBitmap::Callback* callback, void* arg)
+ SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
+
+ template <typename Visitor>
+ void Visit(const Visitor& visitor)
+ EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ // Find and replace a bitmap pointer, this is used by for the bitmap swapping in the GC.
+ void ReplaceBitmap(SpaceBitmap* old_bitmap, SpaceBitmap* new_bitmap)
+ EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
+
+ // Find and replace a object set pointer, this is used by for the bitmap swapping in the GC.
+ void ReplaceObjectSet(SpaceSetMap* old_set, SpaceSetMap* new_set)
+ EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
+
+ HeapBitmap(Heap* heap) : heap_(heap) {
+ }
+
+ private:
+
+ const Heap* const heap_;
+
+ void AddContinuousSpaceBitmap(SpaceBitmap* bitmap);
+ void AddDiscontinuousObjectSet(SpaceSetMap* set);
+
+ // Bitmaps covering continuous spaces.
+ std::vector<SpaceBitmap*> continuous_space_bitmaps_;
+
+ // Sets covering discontinuous spaces.
+ std::vector<SpaceSetMap*> discontinuous_space_sets_;
+
+ friend class art::gc::Heap;
+};
+
+} // namespace accounting
+} // namespace gc
+} // namespace art
+
+#endif // ART_SRC_GC_ACCOUNTING_HEAP_BITMAP_H_
diff --git a/src/gc/accounting/mod_union_table-inl.h b/src/gc/accounting/mod_union_table-inl.h
new file mode 100644
index 0000000000..656af94853
--- /dev/null
+++ b/src/gc/accounting/mod_union_table-inl.h
@@ -0,0 +1,75 @@
+/*
+ * 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_GC_MOD_UNION_TABLE_INL_H_
+#define ART_SRC_GC_MOD_UNION_TABLE_INL_H_
+
+#include "mod_union_table.h"
+
+#include "gc/space/space.h"
+
+namespace art {
+namespace gc {
+namespace accounting {
+
+// A mod-union table to record image references to the Zygote and alloc space.
+class ModUnionTableToZygoteAllocspace : public ModUnionTableReferenceCache {
+public:
+ ModUnionTableToZygoteAllocspace(Heap* heap) : ModUnionTableReferenceCache(heap) {
+ }
+
+ bool AddReference(const mirror::Object* /* obj */, const mirror::Object* ref) {
+ const std::vector<space::ContinuousSpace*>& spaces = GetHeap()->GetContinuousSpaces();
+ typedef std::vector<space::ContinuousSpace*>::const_iterator It;
+ for (It it = spaces.begin(); it != spaces.end(); ++it) {
+ if ((*it)->Contains(ref)) {
+ return (*it)->IsDlMallocSpace();
+ }
+ }
+ // Assume it points to a large object.
+ // TODO: Check.
+ return true;
+ }
+};
+
+// A mod-union table to record Zygote references to the alloc space.
+class ModUnionTableToAllocspace : public ModUnionTableReferenceCache {
+ public:
+ ModUnionTableToAllocspace(Heap* heap) : ModUnionTableReferenceCache(heap) {
+ }
+
+ bool AddReference(const mirror::Object* /* obj */, const mirror::Object* ref) {
+ const std::vector<space::ContinuousSpace*>& spaces = GetHeap()->GetContinuousSpaces();
+ typedef std::vector<space::ContinuousSpace*>::const_iterator It;
+ for (It it = spaces.begin(); it != spaces.end(); ++it) {
+ space::ContinuousSpace* space = *it;
+ if (space->Contains(ref)) {
+ // The allocation space is always considered for collection whereas the Zygote space is
+ //
+ return space->GetGcRetentionPolicy() == space::kGcRetentionPolicyAlwaysCollect;
+ }
+ }
+ // Assume it points to a large object.
+ // TODO: Check.
+ return true;
+ }
+};
+
+} // namespace accounting
+} // namespace gc
+} // namespace art
+
+#endif // ART_SRC_GC_MOD_UNION_TABLE_INL_H_
diff --git a/src/gc/mod_union_table.cc b/src/gc/accounting/mod_union_table.cc
index da950bb9b8..05b68c4922 100644
--- a/src/gc/mod_union_table.cc
+++ b/src/gc/accounting/mod_union_table.cc
@@ -18,15 +18,14 @@
#include "base/stl_util.h"
#include "card_table-inl.h"
-#include "heap.h"
#include "heap_bitmap.h"
-#include "mark_sweep.h"
-#include "mark_sweep-inl.h"
+#include "gc/collector/mark_sweep-inl.h"
+#include "gc/heap.h"
+#include "gc/space/space.h"
#include "mirror/object-inl.h"
#include "mirror/class-inl.h"
#include "mirror/field-inl.h"
#include "mirror/object_array-inl.h"
-#include "space.h"
#include "space_bitmap-inl.h"
#include "thread.h"
#include "UniquePtr.h"
@@ -34,21 +33,25 @@
using namespace art::mirror;
namespace art {
+namespace gc {
+namespace accounting {
class MarkIfReachesAllocspaceVisitor {
public:
- explicit MarkIfReachesAllocspaceVisitor(Heap* const heap, SpaceBitmap* bitmap)
+ explicit MarkIfReachesAllocspaceVisitor(Heap* const heap, accounting::SpaceBitmap* bitmap)
: heap_(heap),
bitmap_(bitmap) {
}
// Extra parameters are required since we use this same visitor signature for checking objects.
- void operator ()(const Object* obj, const Object* ref, const MemberOffset& /* offset */, bool /* is_static */) const {
+ void operator ()(const Object* obj, const Object* ref, const MemberOffset& /* offset */,
+ bool /* is_static */) const {
// TODO: Optimize?
// TODO: C++0x auto
- const Spaces& spaces = heap_->GetSpaces();
- for (Spaces::const_iterator cur = spaces.begin(); cur != spaces.end(); ++cur) {
- if ((*cur)->IsAllocSpace() && (*cur)->Contains(ref)) {
+ const std::vector<space::ContinuousSpace*>& spaces = heap_->GetContinuousSpaces();
+ typedef std::vector<space::ContinuousSpace*>::const_iterator It;
+ for (It cur = spaces.begin(); cur != spaces.end(); ++cur) {
+ if ((*cur)->IsDlMallocSpace() && (*cur)->Contains(ref)) {
bitmap_->Set(obj);
break;
}
@@ -57,12 +60,12 @@ class MarkIfReachesAllocspaceVisitor {
private:
Heap* const heap_;
- SpaceBitmap* bitmap_;
+ accounting::SpaceBitmap* const bitmap_;
};
class ModUnionVisitor {
public:
- explicit ModUnionVisitor(Heap* const heap, SpaceBitmap* bitmap)
+ explicit ModUnionVisitor(Heap* const heap, accounting::SpaceBitmap* bitmap)
: heap_(heap),
bitmap_(bitmap) {
}
@@ -74,11 +77,11 @@ class ModUnionVisitor {
// We don't have an early exit since we use the visitor pattern, an early exit should
// significantly speed this up.
MarkIfReachesAllocspaceVisitor visitor(heap_, bitmap_);
- MarkSweep::VisitObjectReferences(obj, visitor);
+ collector::MarkSweep::VisitObjectReferences(obj, visitor);
}
private:
Heap* const heap_;
- SpaceBitmap* bitmap_;
+ accounting::SpaceBitmap* const bitmap_;
};
class ModUnionClearCardSetVisitor {
@@ -109,65 +112,12 @@ class ModUnionClearCardVisitor {
}
}
private:
- std::vector<byte*>* cleared_cards_;
+ std::vector<byte*>* const cleared_cards_;
};
-ModUnionTableBitmap::ModUnionTableBitmap(Heap* heap) : ModUnionTable(heap) {
- // Prevent fragmentation of the heap which is caused by resizing of the vector.
- // TODO: Make a new vector which uses madvise (basically same as a mark stack).
- cleared_cards_.reserve(32);
- const Spaces& spaces = heap->GetSpaces();
- // Create one heap bitmap per image space.
- // TODO: C++0x auto
- for (Spaces::const_iterator it = spaces.begin(); it != spaces.end(); ++it) {
- ContinuousSpace* space = *it;
- if (space->IsImageSpace()) {
- // The mod-union table is only needed when we have an image space since it's purpose is to
- // cache image roots.
- UniquePtr<SpaceBitmap> bitmap(SpaceBitmap::Create("mod-union table bitmap", space->Begin(),
- space->Size()));
- CHECK(bitmap.get() != NULL) << "Failed to create mod-union bitmap";
- bitmaps_.Put(space, bitmap.release());
- }
- }
-}
-
-ModUnionTableBitmap::~ModUnionTableBitmap() {
- STLDeleteValues(&bitmaps_);
-}
-
-void ModUnionTableBitmap::ClearCards(ContinuousSpace* space) {
- CardTable* card_table = heap_->GetCardTable();
- ModUnionClearCardVisitor visitor(&cleared_cards_);
- // Clear dirty cards in the this image space and update the corresponding mod-union bits.
- card_table->ModifyCardsAtomic(space->Begin(), space->End(), AgeCardVisitor(), visitor);
-}
-
-void ModUnionTableBitmap::Update() {
- CardTable* card_table = heap_->GetCardTable();
- while (!cleared_cards_.empty()) {
- byte* card = cleared_cards_.back();
- cleared_cards_.pop_back();
-
- uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card));
- uintptr_t end = start + CardTable::kCardSize;
- ContinuousSpace* space = heap_->FindSpaceFromObject(reinterpret_cast<Object*>(start));
- SpaceBitmap* bitmap = space->GetLiveBitmap();
-
- // Clear the mod-union bitmap range corresponding to this card so that we don't have any
- // objects marked which do not reach the alloc space.
- bitmap->VisitRange(start, end, SpaceBitmap::ClearVisitor(bitmap));
-
- // At this point we need to update the mod-union bitmap to contain all the objects which reach
- // the alloc space.
- ModUnionVisitor visitor(heap_, bitmap);
- space->GetLiveBitmap()->VisitMarkedRange(start, end, visitor, VoidFunctor());
- }
-}
-
class ModUnionScanImageRootVisitor {
public:
- ModUnionScanImageRootVisitor(MarkSweep* const mark_sweep) : mark_sweep_(mark_sweep) {
+ ModUnionScanImageRootVisitor(collector::MarkSweep* const mark_sweep) : mark_sweep_(mark_sweep) {
}
void operator ()(const Object* root) const
@@ -178,30 +128,10 @@ class ModUnionScanImageRootVisitor {
}
private:
- MarkSweep* const mark_sweep_;
+ collector::MarkSweep* const mark_sweep_;
};
-void ModUnionTableBitmap::MarkReferences(MarkSweep* mark_sweep) {
- // Some tests have no image space, and therefore no mod-union bitmap.
- ModUnionScanImageRootVisitor image_root_scanner(mark_sweep);
- for (BitmapMap::iterator it = bitmaps_.begin(); it != bitmaps_.end(); ++it) {
- const ContinuousSpace* space = it->first;
- uintptr_t begin = reinterpret_cast<uintptr_t>(space->Begin());
- uintptr_t end = reinterpret_cast<uintptr_t>(space->End());
- it->second->VisitMarkedRange(begin, end, image_root_scanner, VoidFunctor());
- }
-}
-
-
-ModUnionTableReferenceCache::ModUnionTableReferenceCache(Heap* heap) : ModUnionTable(heap) {
-
-}
-
-ModUnionTableReferenceCache::~ModUnionTableReferenceCache() {
-
-}
-
-void ModUnionTableReferenceCache::ClearCards(ContinuousSpace* space) {
+void ModUnionTableReferenceCache::ClearCards(space::ContinuousSpace* space) {
CardTable* card_table = GetHeap()->GetCardTable();
ModUnionClearCardSetVisitor visitor(&cleared_cards_);
// Clear dirty cards in the this space and update the corresponding mod-union bits.
@@ -210,9 +140,8 @@ void ModUnionTableReferenceCache::ClearCards(ContinuousSpace* space) {
class AddToReferenceArrayVisitor {
public:
- explicit AddToReferenceArrayVisitor(
- ModUnionTableReferenceCache* const mod_union_table,
- ModUnionTableReferenceCache::ReferenceArray* references)
+ explicit AddToReferenceArrayVisitor(ModUnionTableReferenceCache* mod_union_table,
+ std::vector<const mirror::Object*>* references)
: mod_union_table_(mod_union_table),
references_(references) {
}
@@ -227,41 +156,35 @@ class AddToReferenceArrayVisitor {
}
private:
- ModUnionTableReferenceCache* mod_union_table_;
- ModUnionTable::ReferenceArray* references_;
+ ModUnionTableReferenceCache* const mod_union_table_;
+ std::vector<const mirror::Object*>* const references_;
};
class ModUnionReferenceVisitor {
public:
- explicit ModUnionReferenceVisitor(
- ModUnionTableReferenceCache* const mod_union_table,
- ModUnionTableReferenceCache::ReferenceArray* references)
+ explicit ModUnionReferenceVisitor(ModUnionTableReferenceCache* const mod_union_table,
+ std::vector<const mirror::Object*>* references)
: mod_union_table_(mod_union_table),
references_(references) {
}
void operator ()(const Object* obj) const
- SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_,
- Locks::mutator_lock_) {
+ SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_, Locks::mutator_lock_) {
DCHECK(obj != NULL);
// We don't have an early exit since we use the visitor pattern, an early
// exit should significantly speed this up.
AddToReferenceArrayVisitor visitor(mod_union_table_, references_);
- MarkSweep::VisitObjectReferences(obj, visitor);
+ collector::MarkSweep::VisitObjectReferences(obj, visitor);
}
private:
ModUnionTableReferenceCache* const mod_union_table_;
- ModUnionTable::ReferenceArray* references_;
+ std::vector<const mirror::Object*>* const references_;
};
-
class CheckReferenceVisitor {
public:
- typedef std::set<const Object*> ReferenceSet;
-
- explicit CheckReferenceVisitor(
- ModUnionTableReferenceCache* const mod_union_table,
- const ReferenceSet& references)
+ explicit CheckReferenceVisitor(ModUnionTableReferenceCache* mod_union_table,
+ const std::set<const Object*>& references)
: mod_union_table_(mod_union_table),
references_(references) {
}
@@ -269,13 +192,13 @@ class CheckReferenceVisitor {
// Extra parameters are required since we use this same visitor signature for checking objects.
// TODO: Fixme when anotatalysis works with visitors.
void operator ()(const Object* obj, const Object* ref, const MemberOffset& /* offset */,
- bool /* is_static */) const
+ bool /* is_static */) const
SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_, Locks::mutator_lock_) {
Heap* heap = mod_union_table_->GetHeap();
if (ref != NULL && mod_union_table_->AddReference(obj, ref) &&
references_.find(ref) == references_.end()) {
- ContinuousSpace* from_space = heap->FindSpaceFromObject(obj);
- ContinuousSpace* to_space = heap->FindSpaceFromObject(ref);
+ space::ContinuousSpace* from_space = heap->FindContinuousSpaceFromObject(obj, false);
+ space::ContinuousSpace* to_space = heap->FindContinuousSpaceFromObject(ref, false);
LOG(INFO) << "Object " << reinterpret_cast<const void*>(obj) << "(" << PrettyTypeOf(obj) << ")"
<< "References " << reinterpret_cast<const void*>(ref)
<< "(" << PrettyTypeOf(ref) << ") without being in mod-union table";
@@ -288,83 +211,108 @@ class CheckReferenceVisitor {
private:
ModUnionTableReferenceCache* const mod_union_table_;
- const ReferenceSet& references_;
+ const std::set<const Object*>& references_;
};
class ModUnionCheckReferences {
public:
- typedef std::set<const Object*> ReferenceSet;
-
- explicit ModUnionCheckReferences (
- ModUnionTableReferenceCache* const mod_union_table,
- const ReferenceSet& references)
- : mod_union_table_(mod_union_table),
- references_(references) {
+ explicit ModUnionCheckReferences (ModUnionTableReferenceCache* mod_union_table,
+ const std::set<const Object*>& references)
+ EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
+ : mod_union_table_(mod_union_table), references_(references) {
}
void operator ()(const Object* obj) const NO_THREAD_SAFETY_ANALYSIS {
+ Locks::heap_bitmap_lock_->AssertSharedHeld(Thread::Current());
DCHECK(obj != NULL);
- if (kDebugLocking) {
- Locks::heap_bitmap_lock_->AssertSharedHeld(Thread::Current());
- }
CheckReferenceVisitor visitor(mod_union_table_, references_);
- MarkSweep::VisitObjectReferences(obj, visitor);
+ collector::MarkSweep::VisitObjectReferences(obj, visitor);
}
private:
ModUnionTableReferenceCache* const mod_union_table_;
- const ReferenceSet& references_;
+ const std::set<const Object*>& references_;
};
void ModUnionTableReferenceCache::Verify() {
// Start by checking that everything in the mod union table is marked.
Heap* heap = GetHeap();
- for (ReferenceMap::const_iterator it = references_.begin(); it != references_.end(); ++it) {
- for (ReferenceArray::const_iterator it_ref = it->second.begin(); it_ref != it->second.end();
+ typedef SafeMap<const byte*, std::vector<const mirror::Object*> >::const_iterator It;
+ typedef std::vector<const mirror::Object*>::const_iterator It2;
+ for (It it = references_.begin(), end = references_.end(); it != end; ++it) {
+ for (It2 it_ref = it->second.begin(), end_ref = it->second.end(); it_ref != end_ref;
++it_ref ) {
- DCHECK(heap->GetLiveBitmap()->Test(*it_ref));
+ CHECK(heap->IsLiveObjectLocked(*it_ref));
}
}
// Check the references of each clean card which is also in the mod union table.
- for (ReferenceMap::const_iterator it = references_.begin(); it != references_.end(); ++it) {
+ CardTable* card_table = heap->GetCardTable();
+ for (It it = references_.begin(); it != references_.end(); ++it) {
const byte* card = &*it->first;
if (*card == CardTable::kCardClean) {
std::set<const Object*> reference_set;
- for (ReferenceArray::const_iterator itr = it->second.begin(); itr != it->second.end();++itr) {
+ for (It2 itr = it->second.begin(); itr != it->second.end();++itr) {
reference_set.insert(*itr);
}
ModUnionCheckReferences visitor(this, reference_set);
- CardTable* card_table = heap->GetCardTable();
uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card));
uintptr_t end = start + CardTable::kCardSize;
- SpaceBitmap* live_bitmap =
- heap->FindSpaceFromObject(reinterpret_cast<Object*>(start))->GetLiveBitmap();
+ space::ContinuousSpace* space =
+ heap->FindContinuousSpaceFromObject(reinterpret_cast<Object*>(start), false);
+ SpaceBitmap* live_bitmap = space->GetLiveBitmap();
live_bitmap->VisitMarkedRange(start, end, visitor, VoidFunctor());
}
}
}
+void ModUnionTableReferenceCache::Dump(std::ostream& os) {
+ CardTable* card_table = heap_->GetCardTable();
+ typedef std::set<byte*>::const_iterator It;
+ os << "ModUnionTable cleared cards: [";
+ for (It it = cleared_cards_.begin(); it != cleared_cards_.end(); ++it) {
+ byte* card = *it;
+ uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card));
+ uintptr_t end = start + CardTable::kCardSize;
+ os << reinterpret_cast<void*>(start) << "-" << reinterpret_cast<void*>(end) << ",";
+ }
+ os << "]\nModUnionTable references: [";
+ typedef SafeMap<const byte*, std::vector<const mirror::Object*> >::const_iterator It2;
+ for (It2 it = references_.begin(); it != references_.end(); ++it) {
+ const byte* card = &*it->first;
+ uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card));
+ uintptr_t end = start + CardTable::kCardSize;
+ os << reinterpret_cast<void*>(start) << "-" << reinterpret_cast<void*>(end) << "->{";
+ typedef std::vector<const mirror::Object*>::const_iterator It3;
+ for (It3 itr = it->second.begin(); itr != it->second.end();++itr) {
+ os << reinterpret_cast<const void*>(*itr) << ",";
+ }
+ os << "},";
+ }
+}
+
void ModUnionTableReferenceCache::Update() {
Heap* heap = GetHeap();
CardTable* card_table = heap->GetCardTable();
- ReferenceArray cards_references;
+ std::vector<const mirror::Object*> cards_references;
ModUnionReferenceVisitor visitor(this, &cards_references);
- for (ClearedCards::iterator it = cleared_cards_.begin(); it != cleared_cards_.end(); ++it) {
+ typedef std::set<byte*>::iterator It;
+ for (It it = cleared_cards_.begin(), cc_end = cleared_cards_.end(); it != cc_end; ++it) {
byte* card = *it;
// Clear and re-compute alloc space references associated with this card.
cards_references.clear();
uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card));
uintptr_t end = start + CardTable::kCardSize;
SpaceBitmap* live_bitmap =
- heap->FindSpaceFromObject(reinterpret_cast<Object*>(start))->GetLiveBitmap();
+ heap->FindContinuousSpaceFromObject(reinterpret_cast<Object*>(start), false)->GetLiveBitmap();
live_bitmap->VisitMarkedRange(start, end, visitor, VoidFunctor());
// Update the corresponding references for the card.
// TODO: C++0x auto
- ReferenceMap::iterator found = references_.find(card);
+ SafeMap<const byte*, std::vector<const mirror::Object*> >::iterator
+ found = references_.find(card);
if (found == references_.end()) {
if (cards_references.empty()) {
// No reason to add empty array.
@@ -378,11 +326,14 @@ void ModUnionTableReferenceCache::Update() {
cleared_cards_.clear();
}
-void ModUnionTableReferenceCache::MarkReferences(MarkSweep* mark_sweep) {
+void ModUnionTableReferenceCache::MarkReferences(collector::MarkSweep* mark_sweep) {
// TODO: C++0x auto
size_t count = 0;
- for (ReferenceMap::const_iterator it = references_.begin(); it != references_.end(); ++it) {
- for (ReferenceArray::const_iterator it_ref = it->second.begin(); it_ref != it->second.end(); ++it_ref ) {
+
+ typedef SafeMap<const byte*, std::vector<const mirror::Object*> >::const_iterator It;
+ for (It it = references_.begin(); it != references_.end(); ++it) {
+ typedef std::vector<const mirror::Object*>::const_iterator It2;
+ for (It2 it_ref = it->second.begin(); it_ref != it->second.end(); ++it_ref ) {
mark_sweep->MarkRoot(*it_ref);
++count;
}
@@ -392,15 +343,7 @@ void ModUnionTableReferenceCache::MarkReferences(MarkSweep* mark_sweep) {
}
}
-ModUnionTableCardCache::ModUnionTableCardCache(Heap* heap) : ModUnionTable(heap) {
-
-}
-
-ModUnionTableCardCache::~ModUnionTableCardCache() {
-
-}
-
-void ModUnionTableCardCache::ClearCards(ContinuousSpace* space) {
+void ModUnionTableCardCache::ClearCards(space::ContinuousSpace* space) {
CardTable* card_table = GetHeap()->GetCardTable();
ModUnionClearCardSetVisitor visitor(&cleared_cards_);
// Clear dirty cards in the this space and update the corresponding mod-union bits.
@@ -408,17 +351,46 @@ void ModUnionTableCardCache::ClearCards(ContinuousSpace* space) {
}
// Mark all references to the alloc space(s).
-void ModUnionTableCardCache::MarkReferences(MarkSweep* mark_sweep) {
+void ModUnionTableCardCache::MarkReferences(collector::MarkSweep* mark_sweep) {
CardTable* card_table = heap_->GetCardTable();
ModUnionScanImageRootVisitor visitor(mark_sweep);
- for (ClearedCards::const_iterator it = cleared_cards_.begin(); it != cleared_cards_.end(); ++it) {
+ typedef std::set<byte*>::const_iterator It;
+ It it = cleared_cards_.begin();
+ It cc_end = cleared_cards_.end();
+ if (it != cc_end) {
byte* card = *it;
uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card));
uintptr_t end = start + CardTable::kCardSize;
- SpaceBitmap* live_bitmap =
- heap_->FindSpaceFromObject(reinterpret_cast<Object*>(start))->GetLiveBitmap();
- live_bitmap->VisitMarkedRange(start, end, visitor, VoidFunctor());
+ space::ContinuousSpace* cur_space =
+ heap_->FindContinuousSpaceFromObject(reinterpret_cast<Object*>(start), false);
+ accounting::SpaceBitmap* cur_live_bitmap = cur_space->GetLiveBitmap();
+ cur_live_bitmap->VisitMarkedRange(start, end, visitor, VoidFunctor());
+ for (++it; it != cc_end; ++it) {
+ card = *it;
+ start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card));
+ end = start + CardTable::kCardSize;
+ if (UNLIKELY(!cur_space->Contains(reinterpret_cast<Object*>(start)))) {
+ cur_space = heap_->FindContinuousSpaceFromObject(reinterpret_cast<Object*>(start), false);
+ cur_live_bitmap = cur_space->GetLiveBitmap();
+ }
+ cur_live_bitmap->VisitMarkedRange(start, end, visitor, VoidFunctor());
+ }
+ }
+}
+
+void ModUnionTableCardCache::Dump(std::ostream& os) {
+ CardTable* card_table = heap_->GetCardTable();
+ typedef std::set<byte*>::const_iterator It;
+ os << "ModUnionTable dirty cards: [";
+ for (It it = cleared_cards_.begin(); it != cleared_cards_.end(); ++it) {
+ byte* card = *it;
+ uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card));
+ uintptr_t end = start + CardTable::kCardSize;
+ os << reinterpret_cast<void*>(start) << "-" << reinterpret_cast<void*>(end) << ",";
}
+ os << "]";
}
+} // namespace accounting
+} // namespace gc
} // namespace art
diff --git a/src/gc/mod_union_table.h b/src/gc/accounting/mod_union_table.h
index c0b95357e6..5d25e05658 100644
--- a/src/gc/mod_union_table.h
+++ b/src/gc/accounting/mod_union_table.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ART_SRC_GC_MOD_UNION_TABLE_H_
-#define ART_SRC_GC_MOD_UNION_TABLE_H_
+#ifndef ART_SRC_GC_ACCOUNTING_MOD_UNION_TABLE_H_
+#define ART_SRC_GC_ACCOUNTING_MOD_UNION_TABLE_H_
#include "globals.h"
#include "safe_map.h"
@@ -25,37 +25,47 @@
namespace art {
namespace mirror {
-class Object;
-}
-class ContinuousSpace;
+ class Object;
+} // namespace mirror
+
+namespace gc {
+
+namespace collector {
+ class MarkSweep;
+} // namespace collector
+namespace space {
+ class ContinuousSpace;
+ class Space;
+} // namespace space
+
class Heap;
-class HeapBitmap;
-class MarkSweep;
-class Space;
+
+namespace accounting {
+
class SpaceBitmap;
+class HeapBitmap;
-// Base class
+// The mod-union table is the union of modified cards. It is used to allow the card table to be
+// cleared between GC phases, reducing the number of dirty cards that need to be scanned.
class ModUnionTable {
public:
- typedef std::vector<const mirror::Object*> ReferenceArray;
- typedef std::set<byte*> ClearedCards;
-
ModUnionTable(Heap* heap) : heap_(heap) {
-
}
virtual ~ModUnionTable() {
-
}
- // Clear cards which map to a memory range of a space.
- virtual void ClearCards(ContinuousSpace* space) = 0;
+ // Clear cards which map to a memory range of a space. This doesn't immediately update the
+ // mod-union table, as updating the mod-union table may have an associated cost, such as
+ // determining references to track.
+ virtual void ClearCards(space::ContinuousSpace* space) = 0;
- // Update the mod-union table.
+ // Update the mod-union table using data stored by ClearCards. There may be multiple ClearCards
+ // before a call to update, for example, back-to-back sticky GCs.
virtual void Update() = 0;
- // Mark all references which are stored in the mod union table.
- virtual void MarkReferences(MarkSweep* mark_sweep) = 0;
+ // Mark the bitmaps for all references which are stored in the mod-union table.
+ virtual void MarkReferences(collector::MarkSweep* mark_sweep) = 0;
// Verification, sanity checks that we don't have clean cards which conflict with out cached data
// for said cards. Exclusive lock is required since verify sometimes uses
@@ -63,6 +73,8 @@ class ModUnionTable {
// bitmap or not.
virtual void Verify() EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_) = 0;
+ virtual void Dump(std::ostream& os) = 0;
+
Heap* GetHeap() const {
return heap_;
}
@@ -71,44 +83,14 @@ class ModUnionTable {
Heap* const heap_;
};
-// Bitmap implementation.
-// DEPRECATED, performs strictly less well than merely caching which cards were dirty.
-class ModUnionTableBitmap : public ModUnionTable {
- public:
- ModUnionTableBitmap(Heap* heap);
- virtual ~ModUnionTableBitmap();
-
- // Clear space cards.
- void ClearCards(ContinuousSpace* space);
-
- // Update table based on cleared cards.
- void Update()
- EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
- // Mark all references to the alloc space(s).
- void MarkReferences(MarkSweep* mark_sweep) EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
-
- protected:
- // Cleared card array, used to update the mod-union table.
- std::vector<byte*> cleared_cards_;
-
- // One bitmap per image space.
- // TODO: Add support for Zygote spaces?
- typedef SafeMap<ContinuousSpace*, SpaceBitmap*> BitmapMap;
- BitmapMap bitmaps_;
-};
-
// Reference caching implementation. Caches references pointing to alloc space(s) for each card.
class ModUnionTableReferenceCache : public ModUnionTable {
public:
- typedef SafeMap<const byte*, ReferenceArray > ReferenceMap;
-
- ModUnionTableReferenceCache(Heap* heap);
- virtual ~ModUnionTableReferenceCache();
+ ModUnionTableReferenceCache(Heap* heap) : ModUnionTable(heap) {}
+ virtual ~ModUnionTableReferenceCache() {}
// Clear and store cards for a space.
- void ClearCards(ContinuousSpace* space);
+ void ClearCards(space::ContinuousSpace* space);
// Update table based on cleared cards.
void Update()
@@ -116,7 +98,7 @@ class ModUnionTableReferenceCache : public ModUnionTable {
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Mark all references to the alloc space(s).
- void MarkReferences(MarkSweep* mark_sweep)
+ void MarkReferences(collector::MarkSweep* mark_sweep)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
@@ -127,41 +109,45 @@ class ModUnionTableReferenceCache : public ModUnionTable {
// Function that tells whether or not to add a reference to the table.
virtual bool AddReference(const mirror::Object* obj, const mirror::Object* ref) = 0;
+ void Dump(std::ostream& os);
+
protected:
// Cleared card array, used to update the mod-union table.
- ClearedCards cleared_cards_;
+ std::set<byte*> cleared_cards_;
// Maps from dirty cards to their corresponding alloc space references.
- ReferenceMap references_;
+ SafeMap<const byte*, std::vector<const mirror::Object*> > references_;
};
// Card caching implementation. Keeps track of which cards we cleared and only this information.
class ModUnionTableCardCache : public ModUnionTable {
public:
- typedef SafeMap<const byte*, ReferenceArray > ReferenceMap;
-
- ModUnionTableCardCache(Heap* heap);
- virtual ~ModUnionTableCardCache();
+ ModUnionTableCardCache(Heap* heap) : ModUnionTable(heap) {}
+ virtual ~ModUnionTableCardCache() {}
// Clear and store cards for a space.
- void ClearCards(ContinuousSpace* space);
+ void ClearCards(space::ContinuousSpace* space);
- // Nothing to update.
+ // Nothing to update as all dirty cards were placed into cleared cards during clearing.
void Update() {}
// Mark all references to the alloc space(s).
- void MarkReferences(MarkSweep* mark_sweep)
+ void MarkReferences(collector::MarkSweep* mark_sweep)
EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Nothing to verify.
void Verify() {}
+ void Dump(std::ostream& os);
+
protected:
// Cleared card array, used to update the mod-union table.
- ClearedCards cleared_cards_;
+ std::set<byte*> cleared_cards_;
};
+} // namespace accounting
+} // namespace gc
} // namespace art
-#endif // ART_SRC_GC_MOD_UNION_TABLE_H_
+#endif // ART_SRC_GC_ACCOUNTING_MOD_UNION_TABLE_H_
diff --git a/src/gc/space_bitmap-inl.h b/src/gc/accounting/space_bitmap-inl.h
index dd91403756..a4fd330c8f 100644
--- a/src/gc/space_bitmap-inl.h
+++ b/src/gc/accounting/space_bitmap-inl.h
@@ -14,13 +14,16 @@
* limitations under the License.
*/
-#ifndef ART_SRC_GC_SPACE_BITMAP_INL_H_
-#define ART_SRC_GC_SPACE_BITMAP_INL_H_
+#ifndef ART_SRC_GC_ACCOUNTING_SPACE_BITMAP_INL_H_
+#define ART_SRC_GC_ACCOUNTING_SPACE_BITMAP_INL_H_
#include "base/logging.h"
#include "cutils/atomic-inline.h"
+#include "utils.h"
namespace art {
+namespace gc {
+namespace accounting {
inline bool SpaceBitmap::AtomicTestAndSet(const mirror::Object* obj) {
uintptr_t addr = reinterpret_cast<uintptr_t>(obj);
@@ -136,6 +139,9 @@ inline bool SpaceBitmap::Modify(const mirror::Object* obj, bool do_set) {
}
return (old_word & mask) != 0;
}
+
+} // namespace accounting
+} // namespace gc
} // namespace art
-#endif // ART_SRC_GC_SPACE_BITMAP_INL_H_
+#endif // ART_SRC_GC_ACCOUNTING_SPACE_BITMAP_INL_H_
diff --git a/src/gc/space_bitmap.cc b/src/gc/accounting/space_bitmap.cc
index 773aa1e707..19f1128963 100644
--- a/src/gc/space_bitmap.cc
+++ b/src/gc/accounting/space_bitmap.cc
@@ -14,19 +14,21 @@
* limitations under the License.
*/
-#include "heap_bitmap.h"
-
#include "base/logging.h"
#include "dex_file-inl.h"
+#include "heap_bitmap.h"
#include "mirror/class-inl.h"
#include "mirror/field-inl.h"
#include "mirror/object-inl.h"
#include "mirror/object_array-inl.h"
+#include "object_utils.h"
#include "space_bitmap-inl.h"
#include "UniquePtr.h"
#include "utils.h"
namespace art {
+namespace gc {
+namespace accounting {
std::string SpaceBitmap::GetName() const {
return name_;
@@ -36,6 +38,12 @@ void SpaceBitmap::SetName(const std::string& name) {
name_ = name;
}
+std::string SpaceBitmap::Dump() const {
+ return StringPrintf("%s: %p-%p", name_.c_str(),
+ reinterpret_cast<void*>(HeapBegin()),
+ reinterpret_cast<void*>(HeapLimit()));
+}
+
void SpaceSetMap::Walk(SpaceBitmap::Callback* callback, void* arg) {
for (Objects::iterator it = contained_.begin(); it != contained_.end(); ++it) {
callback(const_cast<mirror::Object*>(*it), arg);
@@ -72,8 +80,6 @@ void SpaceBitmap::SetHeapLimit(uintptr_t new_end) {
// mem_map_->Trim(reinterpret_cast<byte*>(heap_begin_ + bitmap_size_));
}
-// Fill the bitmap with zeroes. Returns the bitmap's memory to the
-// system as a side-effect.
void SpaceBitmap::Clear() {
if (bitmap_begin_ != NULL) {
// This returns the memory to the system. Successive page faults
@@ -164,14 +170,6 @@ void SpaceBitmap::SweepWalk(const SpaceBitmap& live_bitmap,
}
}
-} // namespace art
-
-// Support needed for in order traversal
-#include "mirror/object.h"
-#include "object_utils.h"
-
-namespace art {
-
static void WalkFieldsInOrder(SpaceBitmap* visited, SpaceBitmap::Callback* callback, mirror::Object* obj,
void* arg);
@@ -273,10 +271,6 @@ void SpaceSetMap::SetName(const std::string& name) {
name_ = name;
}
-SpaceSetMap::SpaceSetMap(const std::string& name) : name_(name) {
-
-}
-
void SpaceSetMap::CopyFrom(const SpaceSetMap& space_set) {
contained_ = space_set.contained_;
}
@@ -287,6 +281,8 @@ std::ostream& operator << (std::ostream& stream, const SpaceBitmap& bitmap) {
<< "begin=" << reinterpret_cast<const void*>(bitmap.HeapBegin())
<< ",end=" << reinterpret_cast<const void*>(bitmap.HeapLimit())
<< "]";
- }
+}
+} // namespace accounting
+} // namespace gc
} // namespace art
diff --git a/src/gc/space_bitmap.h b/src/gc/accounting/space_bitmap.h
index 6bc06d600d..bb487d88d0 100644
--- a/src/gc/space_bitmap.h
+++ b/src/gc/accounting/space_bitmap.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ART_SRC_GC_SPACE_BITMAP_H_
-#define ART_SRC_GC_SPACE_BITMAP_H_
+#ifndef ART_SRC_GC_ACCOUNTING_SPACE_BITMAP_H_
+#define ART_SRC_GC_ACCOUNTING_SPACE_BITMAP_H_
#include "locks.h"
#include "globals.h"
@@ -28,12 +28,17 @@
#include <vector>
namespace art {
+
namespace mirror {
-class Object;
+ class Object;
} // namespace mirror
+namespace gc {
+namespace accounting {
+
class SpaceBitmap {
public:
+ // Alignment of objects within spaces.
static const size_t kAlignment = 8;
typedef void Callback(mirror::Object* obj, void* arg);
@@ -52,7 +57,7 @@ class SpaceBitmap {
// <index> is the index of .bits that contains the bit representing
// <offset>.
static size_t OffsetToIndex(size_t offset) {
- return offset / kAlignment / kBitsPerWord;
+ return offset / kAlignment / kBitsPerWord;
}
static uintptr_t IndexToOffset(size_t index) {
@@ -75,6 +80,7 @@ class SpaceBitmap {
// Returns true if the object was previously marked.
bool AtomicTestAndSet(const mirror::Object* obj);
+ // Fill the bitmap with zeroes. Returns the bitmap's memory to the system as a side-effect.
void Clear();
bool Test(const mirror::Object* obj) const;
@@ -160,6 +166,8 @@ class SpaceBitmap {
std::string GetName() const;
void SetName(const std::string& name);
+ std::string Dump() const;
+
const void* GetObjectWordAddress(const mirror::Object* obj) const {
uintptr_t addr = reinterpret_cast<uintptr_t>(obj);
const uintptr_t offset = addr - heap_begin_;
@@ -236,7 +244,8 @@ class SpaceSetMap {
}
}
- SpaceSetMap(const std::string& name);
+ SpaceSetMap(const std::string& name) : name_(name) {}
+ ~SpaceSetMap() {}
Objects& GetObjects() {
return contained_;
@@ -249,6 +258,8 @@ class SpaceSetMap {
std::ostream& operator << (std::ostream& stream, const SpaceBitmap& bitmap);
+} // namespace accounting
+} // namespace gc
} // namespace art
-#endif // ART_SRC_GC_SPACE_BITMAP_H_
+#endif // ART_SRC_GC_ACCOUNTING_SPACE_BITMAP_H_
diff --git a/src/gc/space_bitmap_test.cc b/src/gc/accounting/space_bitmap_test.cc
index 4645659470..d00d7c2739 100644
--- a/src/gc/space_bitmap_test.cc
+++ b/src/gc/accounting/space_bitmap_test.cc
@@ -17,7 +17,6 @@
#include "space_bitmap.h"
#include "common_test.h"
-#include "dlmalloc.h"
#include "globals.h"
#include "space_bitmap-inl.h"
#include "UniquePtr.h"
@@ -25,6 +24,8 @@
#include <stdint.h>
namespace art {
+namespace gc {
+namespace accounting {
class SpaceBitmapTest : public CommonTest {
public:
@@ -87,4 +88,6 @@ TEST_F(SpaceBitmapTest, ScanRange) {
}
}
+} // namespace accounting
+} // namespace gc
} // namespace art
diff --git a/src/dlmalloc.cc b/src/gc/allocator/dlmalloc.cc
index 1d62d2011e..7584b6e6b9 100644
--- a/src/dlmalloc.cc
+++ b/src/gc/allocator/dlmalloc.cc
@@ -45,3 +45,28 @@ static void art_heap_corruption(const char* function) {
static void art_heap_usage_error(const char* function, void* p) {
LOG(FATAL) << "Incorrect use of function '" << function << "' argument " << p << " not expected";
}
+
+#include "globals.h"
+#include "utils.h"
+#include <sys/mman.h>
+
+using namespace art;
+extern "C" void DlmallocMadviseCallback(void* start, void* end, size_t used_bytes, void* arg) {
+ // Is this chunk in use?
+ if (used_bytes != 0) {
+ return;
+ }
+ // Do we have any whole pages to give back?
+ start = reinterpret_cast<void*>(RoundUp(reinterpret_cast<uintptr_t>(start), kPageSize));
+ end = reinterpret_cast<void*>(RoundDown(reinterpret_cast<uintptr_t>(end), kPageSize));
+ if (end > start) {
+ size_t length = reinterpret_cast<byte*>(end) - reinterpret_cast<byte*>(start);
+ int rc = madvise(start, length, MADV_DONTNEED);
+ if (UNLIKELY(rc != 0)) {
+ errno = rc;
+ PLOG(FATAL) << "madvise failed during heap trimming";
+ }
+ size_t* reclaimed = reinterpret_cast<size_t*>(arg);
+ *reclaimed += length;
+ }
+}
diff --git a/src/dlmalloc.h b/src/gc/allocator/dlmalloc.h
index b6759a098c..6b02a44ffe 100644
--- a/src/dlmalloc.h
+++ b/src/gc/allocator/dlmalloc.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ART_SRC_DLMALLOC_H_
-#define ART_SRC_DLMALLOC_H_
+#ifndef ART_SRC_GC_ALLOCATOR_DLMALLOC_H_
+#define ART_SRC_GC_ALLOCATOR_DLMALLOC_H_
// Configure dlmalloc for mspaces.
#define HAVE_MMAP 0
@@ -33,4 +33,8 @@
extern "C" void dlmalloc_inspect_all(void(*handler)(void*, void *, size_t, void*), void* arg);
extern "C" int dlmalloc_trim(size_t);
-#endif // ART_SRC_DLMALLOC_H_
+// Callback for dlmalloc_inspect_all or mspace_inspect_all that will madvise(2) unused
+// pages back to the kernel.
+extern "C" void DlmallocMadviseCallback(void* start, void* end, size_t used_bytes, void* /*arg*/);
+
+#endif // ART_SRC_GC_ALLOCATOR_DLMALLOC_H_
diff --git a/src/gc/collector/garbage_collector.cc b/src/gc/collector/garbage_collector.cc
new file mode 100644
index 0000000000..378a971250
--- /dev/null
+++ b/src/gc/collector/garbage_collector.cc
@@ -0,0 +1,150 @@
+/*
+ * 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.
+ */
+
+#define ATRACE_TAG ATRACE_TAG_DALVIK
+
+#include <stdio.h>
+#include <cutils/trace.h>
+
+#include "garbage_collector.h"
+
+#include "base/logging.h"
+#include "base/mutex-inl.h"
+#include "gc/accounting/heap_bitmap.h"
+#include "gc/space/large_object_space.h"
+#include "gc/space/space-inl.h"
+#include "thread.h"
+#include "thread_list.h"
+
+namespace art {
+namespace gc {
+namespace collector {
+
+GarbageCollector::GarbageCollector(Heap* heap, const std::string& name)
+ : heap_(heap),
+ name_(name),
+ verbose_(VLOG_IS_ON(heap)),
+ duration_ns_(0),
+ timings_(name_.c_str(), true, verbose_),
+ cumulative_timings_(name) {
+ ResetCumulativeStatistics();
+}
+
+bool GarbageCollector::HandleDirtyObjectsPhase() {
+ DCHECK(IsConcurrent());
+ return true;
+}
+
+void GarbageCollector::RegisterPause(uint64_t nano_length) {
+ pause_times_.push_back(nano_length);
+}
+
+void GarbageCollector::ResetCumulativeStatistics() {
+ cumulative_timings_.Reset();
+ total_time_ns_ = 0;
+ total_paused_time_ns_ = 0;
+ total_freed_objects_ = 0;
+ total_freed_bytes_ = 0;
+}
+
+void GarbageCollector::Run() {
+ Thread* self = Thread::Current();
+ ThreadList* thread_list = Runtime::Current()->GetThreadList();
+
+ uint64_t start_time = NanoTime();
+ pause_times_.clear();
+ duration_ns_ = 0;
+
+ InitializePhase();
+
+ if (!IsConcurrent()) {
+ // Pause is the entire length of the GC.
+ uint64_t pause_start = NanoTime();
+ ATRACE_BEGIN("Application threads suspended");
+ thread_list->SuspendAll();
+ MarkingPhase();
+ ReclaimPhase();
+ thread_list->ResumeAll();
+ ATRACE_END();
+ uint64_t pause_end = NanoTime();
+ pause_times_.push_back(pause_end - pause_start);
+ } else {
+ {
+ ReaderMutexLock mu(self, *Locks::mutator_lock_);
+ MarkingPhase();
+ }
+ bool done = false;
+ while (!done) {
+ uint64_t pause_start = NanoTime();
+ ATRACE_BEGIN("Application threads suspended");
+ thread_list->SuspendAll();
+ done = HandleDirtyObjectsPhase();
+ thread_list->ResumeAll();
+ ATRACE_END();
+ uint64_t pause_end = NanoTime();
+ pause_times_.push_back(pause_end - pause_start);
+ }
+ {
+ ReaderMutexLock mu(self, *Locks::mutator_lock_);
+ ReclaimPhase();
+ }
+ }
+
+ uint64_t end_time = NanoTime();
+ duration_ns_ = end_time - start_time;
+
+ FinishPhase();
+}
+
+void GarbageCollector::SwapBitmaps() {
+ // Swap the live and mark bitmaps for each alloc space. This is needed since sweep re-swaps
+ // these bitmaps. The bitmap swapping is an optimization so that we do not need to clear the live
+ // bits of dead objects in the live bitmap.
+ const GcType gc_type = GetGcType();
+ const std::vector<space::ContinuousSpace*>& cont_spaces = GetHeap()->GetContinuousSpaces();
+ // TODO: C++0x
+ typedef std::vector<space::ContinuousSpace*>::const_iterator It;
+ for (It it = cont_spaces.begin(), end = cont_spaces.end(); it != end; ++it) {
+ space::ContinuousSpace* space = *it;
+ // We never allocate into zygote spaces.
+ if (space->GetGcRetentionPolicy() == space::kGcRetentionPolicyAlwaysCollect ||
+ (gc_type == kGcTypeFull &&
+ space->GetGcRetentionPolicy() == space::kGcRetentionPolicyFullCollect)) {
+ accounting::SpaceBitmap* live_bitmap = space->GetLiveBitmap();
+ accounting::SpaceBitmap* mark_bitmap = space->GetMarkBitmap();
+ if (live_bitmap != mark_bitmap) {
+ heap_->GetLiveBitmap()->ReplaceBitmap(live_bitmap, mark_bitmap);
+ heap_->GetMarkBitmap()->ReplaceBitmap(mark_bitmap, live_bitmap);
+ space->AsDlMallocSpace()->SwapBitmaps();
+ }
+ }
+ }
+ const std::vector<space::DiscontinuousSpace*>& disc_spaces = GetHeap()->GetDiscontinuousSpaces();
+ // TODO: C++0x
+ typedef std::vector<space::DiscontinuousSpace*>::const_iterator It2;
+ for (It2 it = disc_spaces.begin(), end = disc_spaces.end(); it != end; ++it) {
+ space::LargeObjectSpace* space = down_cast<space::LargeObjectSpace*>(*it);
+ accounting::SpaceSetMap* live_set = space->GetLiveObjects();
+ accounting::SpaceSetMap* mark_set = space->GetMarkObjects();
+ heap_->GetLiveBitmap()->ReplaceObjectSet(live_set, mark_set);
+ heap_->GetMarkBitmap()->ReplaceObjectSet(mark_set, live_set);
+ space->SwapBitmaps();
+ }
+}
+
+} // namespace collector
+} // namespace gc
+} // namespace art
diff --git a/src/gc/garbage_collector.h b/src/gc/collector/garbage_collector.h
index a1014c2c7f..1ab395775b 100644
--- a/src/gc/garbage_collector.h
+++ b/src/gc/collector/garbage_collector.h
@@ -17,28 +17,38 @@
#ifndef ART_SRC_GC_GARBAGE_COLLECTOR_H_
#define ART_SRC_GC_GARBAGE_COLLECTOR_H_
+#include "gc_type.h"
#include "locks.h"
+#include "base/timing_logger.h"
#include <stdint.h>
#include <vector>
namespace art {
+namespace gc {
class Heap;
+namespace collector {
+
class GarbageCollector {
public:
// Returns true iff the garbage collector is concurrent.
virtual bool IsConcurrent() const = 0;
- GarbageCollector(Heap* heap);
+ GarbageCollector(Heap* heap, const std::string& name);
+ virtual ~GarbageCollector() { }
+
+ const char* GetName() const {
+ return name_.c_str();
+ }
- virtual ~GarbageCollector();
+ virtual GcType GetGcType() const = 0;
// Run the garbage collector.
void Run();
- Heap* GetHeap() {
+ Heap* GetHeap() const {
return heap_;
}
@@ -48,16 +58,28 @@ class GarbageCollector {
}
// Returns how long the GC took to complete in nanoseconds.
- uint64_t GetDuration() const {
- return duration_;
+ uint64_t GetDurationNs() const {
+ return duration_ns_;
}
+ void RegisterPause(uint64_t nano_length);
+
+ base::NewTimingLogger& GetTimings() {
+ return timings_;
+ }
- virtual std::string GetName() const = 0;
+ CumulativeLogger& GetCumulativeTimings() {
+ return cumulative_timings_;
+ }
- void RegisterPause(uint64_t nano_length);
+ void ResetCumulativeStatistics();
+
+ // Swap the live and mark bitmaps of spaces that are active for the collector. For partial GC,
+ // this is the allocation space, for full GC then we swap the zygote bitmaps too.
+ void SwapBitmaps() EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
protected:
+
// The initial phase. Done without mutators paused.
virtual void InitializePhase() = 0;
@@ -73,11 +95,28 @@ class GarbageCollector {
// Called after the GC is finished. Done without mutators paused.
virtual void FinishPhase() = 0;
- Heap* heap_;
+ Heap* const heap_;
+
+ std::string name_;
+
+ const bool verbose_;
+
+ uint64_t duration_ns_;
+ base::NewTimingLogger timings_;
+
+ // Cumulative statistics.
+ uint64_t total_time_ns_;
+ uint64_t total_paused_time_ns_;
+ uint64_t total_freed_objects_;
+ uint64_t total_freed_bytes_;
+
+ CumulativeLogger cumulative_timings_;
+
std::vector<uint64_t> pause_times_;
- uint64_t duration_;
};
+} // namespace collector
+} // namespace gc
} // namespace art
#endif // ART_SRC_GC_GARBAGE_COLLECTOR_H_
diff --git a/src/gc/collector/gc_type.cc b/src/gc/collector/gc_type.cc
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/gc/collector/gc_type.cc
diff --git a/src/gc/gc_type.h b/src/gc/collector/gc_type.h
index 908f038ff2..bb25bb93f9 100644
--- a/src/gc/gc_type.h
+++ b/src/gc/collector/gc_type.h
@@ -14,26 +14,33 @@
* limitations under the License.
*/
-#ifndef ART_SRC_GC_GC_TYPE_H_
-#define ART_SRC_GC_GC_TYPE_H_
+#ifndef ART_SRC_GC_COLLECTOR_GC_TYPE_H_
+#define ART_SRC_GC_COLLECTOR_GC_TYPE_H_
+
+#include <ostream>
namespace art {
+namespace gc {
+namespace collector {
-// The ordering of the enum matters, it is used to determine which GCs are run first.
+// The type of collection to be performed. The ordering of the enum matters, it is used to
+// determine which GCs are run first.
enum GcType {
- // No Gc
+ // Placeholder for when no GC has been performed.
kGcTypeNone,
- // Sticky mark bits "generational" GC.
+ // Sticky mark bits GC that attempts to only free objects allocated since the last GC.
kGcTypeSticky,
- // Partial GC, over only the alloc space.
+ // Partial GC that marks the application heap but not the Zygote.
kGcTypePartial,
- // Full GC
+ // Full GC that marks and frees in both the application and Zygote heap.
kGcTypeFull,
- // Number of different Gc types.
+ // Number of different GC types.
kGcTypeMax,
};
std::ostream& operator<<(std::ostream& os, const GcType& policy);
+} // namespace collector
+} // namespace gc
} // namespace art
-#endif // ART_SRC_GC_GC_TYPE_H_
+#endif // ART_SRC_GC_COLLECTOR_GC_TYPE_H_
diff --git a/src/gc/mark_sweep-inl.h b/src/gc/collector/mark_sweep-inl.h
index 726502330b..ea9fced84a 100644
--- a/src/gc/mark_sweep-inl.h
+++ b/src/gc/collector/mark_sweep-inl.h
@@ -17,12 +17,16 @@
#ifndef ART_SRC_GC_MARK_SWEEP_INL_H_
#define ART_SRC_GC_MARK_SWEEP_INL_H_
-#include "heap.h"
+#include "gc/collector/mark_sweep.h"
+
+#include "gc/heap.h"
#include "mirror/class.h"
#include "mirror/field.h"
#include "mirror/object_array.h"
namespace art {
+namespace gc {
+namespace collector {
template <typename MarkVisitor>
inline void MarkSweep::ScanObjectVisit(const mirror::Object* obj, const MarkVisitor& visitor) {
@@ -154,6 +158,8 @@ inline void MarkSweep::VisitObjectArrayReferences(const mirror::ObjectArray<mirr
}
}
+} // namespace collector
+} // namespace gc
} // namespace art
#endif // ART_SRC_GC_MARK_SWEEP_INL_H_
diff --git a/src/gc/mark_sweep.cc b/src/gc/collector/mark_sweep.cc
index 25b4b78356..d54fec6d9f 100644
--- a/src/gc/mark_sweep.cc
+++ b/src/gc/collector/mark_sweep.cc
@@ -25,13 +25,16 @@
#include "base/macros.h"
#include "base/mutex-inl.h"
#include "base/timing_logger.h"
-#include "card_table.h"
-#include "card_table-inl.h"
-#include "heap.h"
+#include "gc/accounting/card_table-inl.h"
+#include "gc/accounting/heap_bitmap.h"
+#include "gc/accounting/space_bitmap-inl.h"
+#include "gc/heap.h"
+#include "gc/space/image_space.h"
+#include "gc/space/large_object_space.h"
+#include "gc/space/space-inl.h"
#include "indirect_reference_table.h"
#include "intern_table.h"
#include "jni_internal.h"
-#include "large_object_space.h"
#include "monitor.h"
#include "mark_sweep-inl.h"
#include "mirror/class-inl.h"
@@ -43,15 +46,15 @@
#include "mirror/object_array.h"
#include "mirror/object_array-inl.h"
#include "runtime.h"
-#include "space.h"
-#include "space_bitmap-inl.h"
-#include "thread.h"
+#include "thread-inl.h"
#include "thread_list.h"
#include "verifier/method_verifier.h"
using namespace art::mirror;
namespace art {
+namespace gc {
+namespace collector {
// Performance options.
static const bool kParallelMarkStack = true;
@@ -68,7 +71,6 @@ static const bool kCountJavaLangRefs = false;
class SetFingerVisitor {
public:
SetFingerVisitor(MarkSweep* const mark_sweep) : mark_sweep_(mark_sweep) {
-
}
void operator ()(void* finger) const {
@@ -79,13 +81,7 @@ class SetFingerVisitor {
MarkSweep* const mark_sweep_;
};
-std::string MarkSweep::GetName() const {
- std::ostringstream ss;
- ss << (IsConcurrent() ? "Concurrent" : "") << GetGcType();
- return ss.str();
-}
-
-void MarkSweep::ImmuneSpace(ContinuousSpace* space) {
+void MarkSweep::ImmuneSpace(space::ContinuousSpace* space) {
// Bind live to mark bitmap if necessary.
if (space->GetLiveBitmap() != space->GetMarkBitmap()) {
BindLiveToMarkBitmap(space);
@@ -97,54 +93,68 @@ void MarkSweep::ImmuneSpace(ContinuousSpace* space) {
SetImmuneRange(reinterpret_cast<Object*>(space->Begin()),
reinterpret_cast<Object*>(space->End()));
} else {
- const Spaces& spaces = GetHeap()->GetSpaces();
- const ContinuousSpace* prev_space = NULL;
- // Find out if the previous space is immune.
- // TODO: C++0x
- for (Spaces::const_iterator it = spaces.begin(); it != spaces.end(); ++it) {
- if (*it == space) {
- break;
- }
- prev_space = *it;
+ const std::vector<space::ContinuousSpace*>& spaces = GetHeap()->GetContinuousSpaces();
+ const space::ContinuousSpace* prev_space = NULL;
+ // Find out if the previous space is immune.
+ // TODO: C++0x
+ typedef std::vector<space::ContinuousSpace*>::const_iterator It;
+ for (It it = spaces.begin(), end = spaces.end(); it != end; ++it) {
+ if (*it == space) {
+ break;
}
+ prev_space = *it;
+ }
- // If previous space was immune, then extend the immune region.
- if (prev_space != NULL &&
- immune_begin_ <= reinterpret_cast<Object*>(prev_space->Begin()) &&
- immune_end_ >= reinterpret_cast<Object*>(prev_space->End())) {
+ // If previous space was immune, then extend the immune region. Relies on continuous spaces
+ // being sorted by Heap::AddContinuousSpace.
+ if (prev_space != NULL &&
+ immune_begin_ <= reinterpret_cast<Object*>(prev_space->Begin()) &&
+ immune_end_ >= reinterpret_cast<Object*>(prev_space->End())) {
immune_begin_ = std::min(reinterpret_cast<Object*>(space->Begin()), immune_begin_);
immune_end_ = std::max(reinterpret_cast<Object*>(space->End()), immune_end_);
}
}
}
-// Bind the live bits to the mark bits of bitmaps based on the gc type.
void MarkSweep::BindBitmaps() {
- Spaces& spaces = GetHeap()->GetSpaces();
+ const std::vector<space::ContinuousSpace*>& spaces = GetHeap()->GetContinuousSpaces();
WriterMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_);
// Mark all of the spaces we never collect as immune.
- for (Spaces::iterator it = spaces.begin(); it != spaces.end(); ++it) {
- ContinuousSpace* space = *it;
- if (space->GetGcRetentionPolicy() == kGcRetentionPolicyNeverCollect) {
+ typedef std::vector<space::ContinuousSpace*>::const_iterator It;
+ for (It it = spaces.begin(), end = spaces.end(); it != end; ++it) {
+ space::ContinuousSpace* space = *it;
+ if (space->GetGcRetentionPolicy() == space::kGcRetentionPolicyNeverCollect) {
ImmuneSpace(space);
}
}
}
-MarkSweep::MarkSweep(Heap* heap, bool is_concurrent)
- : GarbageCollector(heap),
+MarkSweep::MarkSweep(Heap* heap, bool is_concurrent, const std::string& name_prefix)
+ : GarbageCollector(heap,
+ name_prefix + (name_prefix.empty() ? "" : " ") +
+ (is_concurrent ? "concurrent mark sweep": "mark sweep")),
+ current_mark_bitmap_(NULL),
+ java_lang_Class_(NULL),
+ mark_stack_(NULL),
+ finger_(NULL),
+ immune_begin_(NULL),
+ immune_end_(NULL),
+ soft_reference_list_(NULL),
+ weak_reference_list_(NULL),
+ finalizer_reference_list_(NULL),
+ phantom_reference_list_(NULL),
+ cleared_reference_list_(NULL),
gc_barrier_(new Barrier(0)),
large_object_lock_("mark sweep large object lock", kMarkSweepLargeObjectLock),
mark_stack_expand_lock_("mark sweep mark stack expand lock"),
is_concurrent_(is_concurrent),
- timings_(GetName(), true),
- cumulative_timings_(GetName()) {
- cumulative_timings_.SetName(GetName());
- ResetCumulativeStatistics();
+ clear_soft_references_(false) {
}
void MarkSweep::InitializePhase() {
+ timings_.Reset();
+ timings_.StartSplit("InitializePhase");
mark_stack_ = GetHeap()->mark_stack_.get();
DCHECK(mark_stack_ != NULL);
finger_ = NULL;
@@ -169,34 +179,31 @@ void MarkSweep::InitializePhase() {
java_lang_Class_ = Class::GetJavaLangClass();
CHECK(java_lang_Class_ != NULL);
FindDefaultMarkBitmap();
- // Mark any concurrent roots as dirty since we need to scan them at least once during this GC.
- Runtime::Current()->DirtyRoots();
- timings_.Reset();
// Do any pre GC verification.
heap_->PreGcVerification(this);
}
void MarkSweep::ProcessReferences(Thread* self) {
+ timings_.NewSplit("ProcessReferences");
WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
ProcessReferences(&soft_reference_list_, clear_soft_references_, &weak_reference_list_,
&finalizer_reference_list_, &phantom_reference_list_);
- timings_.AddSplit("ProcessReferences");
}
bool MarkSweep::HandleDirtyObjectsPhase() {
Thread* self = Thread::Current();
- ObjectStack* allocation_stack = GetHeap()->allocation_stack_.get();
+ accounting::ObjectStack* allocation_stack = GetHeap()->allocation_stack_.get();
Locks::mutator_lock_->AssertExclusiveHeld(self);
{
+ timings_.NewSplit("ReMarkRoots");
WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
// Re-mark root set.
ReMarkRoots();
- timings_.AddSplit("ReMarkRoots");
// Scan dirty objects, this is only required if we are not doing concurrent GC.
- RecursiveMarkDirtyObjects(CardTable::kCardDirty);
+ RecursiveMarkDirtyObjects(accounting::CardTable::kCardDirty);
}
ProcessReferences(self);
@@ -206,15 +213,17 @@ bool MarkSweep::HandleDirtyObjectsPhase() {
WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
// This second sweep makes sure that we don't have any objects in the live stack which point to
// freed objects. These cause problems since their references may be previously freed objects.
- SweepArray(timings_, allocation_stack, false);
+ SweepArray(allocation_stack, false);
} else {
+ timings_.NewSplit("UnMarkAllocStack");
WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
- // We only sweep over the live stack, and the live stack should not intersect with the
- // allocation stack, so it should be safe to UnMark anything in the allocation stack as live.
+ // The allocation stack contains things allocated since the start of the GC. These may have been
+ // marked during this GC meaning they won't be eligible for reclaiming in the next sticky GC.
+ // Remove these objects from the mark bitmaps so that they will be eligible for sticky
+ // collection.
heap_->UnMarkAllocStack(GetHeap()->alloc_space_->GetMarkBitmap(),
- GetHeap()->large_object_space_->GetMarkObjects(),
- allocation_stack);
- timings_.AddSplit("UnMarkAllocStack");
+ GetHeap()->large_object_space_->GetMarkObjects(),
+ allocation_stack);
}
return true;
}
@@ -227,31 +236,30 @@ void MarkSweep::MarkingPhase() {
Heap* heap = GetHeap();
Thread* self = Thread::Current();
+ timings_.NewSplit("BindBitmaps");
BindBitmaps();
FindDefaultMarkBitmap();
- timings_.AddSplit("BindBitmaps");
-
// Process dirty cards and add dirty cards to mod union tables.
heap->ProcessCards(timings_);
// Need to do this before the checkpoint since we don't want any threads to add references to
// the live stack during the recursive mark.
+ timings_.NewSplit("SwapStacks");
heap->SwapStacks();
- timings_.AddSplit("SwapStacks");
WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
if (Locks::mutator_lock_->IsExclusiveHeld(self)) {
// If we exclusively hold the mutator lock, all threads must be suspended.
+ timings_.NewSplit("MarkRoots");
MarkRoots();
- timings_.AddSplit("MarkConcurrentRoots");
} else {
- MarkRootsCheckpoint();
- timings_.AddSplit("MarkRootsCheckpoint");
+ timings_.NewSplit("MarkRootsCheckpoint");
+ MarkRootsCheckpoint(self);
+ timings_.NewSplit("MarkNonThreadRoots");
MarkNonThreadRoots();
- timings_.AddSplit("MarkNonThreadRoots");
}
+ timings_.NewSplit("MarkConcurrentRoots");
MarkConcurrentRoots();
- timings_.AddSplit("MarkConcurrentRoots");
heap->UpdateAndMarkModUnion(this, timings_, GetGcType());
MarkReachableObjects();
@@ -260,12 +268,12 @@ void MarkSweep::MarkingPhase() {
void MarkSweep::MarkReachableObjects() {
// Mark everything allocated since the last as GC live so that we can sweep concurrently,
// knowing that new allocations won't be marked as live.
- ObjectStack* live_stack = heap_->GetLiveStack();
+ timings_.NewSplit("MarkStackAsLive");
+ accounting::ObjectStack* live_stack = heap_->GetLiveStack();
heap_->MarkAllocStack(heap_->alloc_space_->GetLiveBitmap(),
heap_->large_object_space_->GetLiveObjects(),
live_stack);
live_stack->Reset();
- timings_.AddSplit("MarkStackAsLive");
// Recursively mark all the non-image bits set in the mark bitmap.
RecursiveMark();
DisableFinger();
@@ -289,60 +297,31 @@ void MarkSweep::ReclaimPhase() {
WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
// Reclaim unmarked objects.
- Sweep(timings_, false);
+ Sweep(false);
// Swap the live and mark bitmaps for each space which we modified space. This is an
// optimization that enables us to not clear live bits inside of the sweep. Only swaps unbound
// bitmaps.
+ timings_.NewSplit("SwapBitmaps");
SwapBitmaps();
- timings_.AddSplit("SwapBitmaps");
// Unbind the live and mark bitmaps.
UnBindBitmaps();
}
}
-void MarkSweep::SwapBitmaps() {
- // Swap the live and mark bitmaps for each alloc space. This is needed since sweep re-swaps
- // these bitmaps. The bitmap swapping is an optimization so that we do not need to clear the live
- // bits of dead objects in the live bitmap.
- const GcType gc_type = GetGcType();
- // TODO: C++0x
- Spaces& spaces = heap_->GetSpaces();
- for (Spaces::iterator it = spaces.begin(); it != spaces.end(); ++it) {
- ContinuousSpace* space = *it;
- // We never allocate into zygote spaces.
- if (space->GetGcRetentionPolicy() == kGcRetentionPolicyAlwaysCollect ||
- (gc_type == kGcTypeFull &&
- space->GetGcRetentionPolicy() == kGcRetentionPolicyFullCollect)) {
- SpaceBitmap* live_bitmap = space->GetLiveBitmap();
- SpaceBitmap* mark_bitmap = space->GetMarkBitmap();
- if (live_bitmap != mark_bitmap) {
- heap_->GetLiveBitmap()->ReplaceBitmap(live_bitmap, mark_bitmap);
- heap_->GetMarkBitmap()->ReplaceBitmap(mark_bitmap, live_bitmap);
- space->AsAllocSpace()->SwapBitmaps();
- }
- }
- }
- SwapLargeObjects();
-}
-
-void MarkSweep::SwapLargeObjects() {
- LargeObjectSpace* large_object_space = heap_->GetLargeObjectsSpace();
- large_object_space->SwapBitmaps();
- heap_->GetLiveBitmap()->SetLargeObjects(large_object_space->GetLiveObjects());
- heap_->GetMarkBitmap()->SetLargeObjects(large_object_space->GetMarkObjects());
-}
-
void MarkSweep::SetImmuneRange(Object* begin, Object* end) {
immune_begin_ = begin;
immune_end_ = end;
}
void MarkSweep::FindDefaultMarkBitmap() {
- const Spaces& spaces = heap_->GetSpaces();
- for (Spaces::const_iterator it = spaces.begin(); it != spaces.end(); ++it) {
- if ((*it)->GetGcRetentionPolicy() == kGcRetentionPolicyAlwaysCollect) {
+ const std::vector<space::ContinuousSpace*>& spaces = GetHeap()->GetContinuousSpaces();
+ // TODO: C++0x
+ typedef std::vector<space::ContinuousSpace*>::const_iterator It;
+ for (It it = spaces.begin(), end = spaces.end(); it != end; ++it) {
+ space::ContinuousSpace* space = *it;
+ if (space->GetGcRetentionPolicy() == space::kGcRetentionPolicyAlwaysCollect) {
current_mark_bitmap_ = (*it)->GetMarkBitmap();
CHECK(current_mark_bitmap_ != NULL);
return;
@@ -389,10 +368,10 @@ inline void MarkSweep::MarkObjectNonNull(const Object* obj, bool check_finger) {
// Try to take advantage of locality of references within a space, failing this find the space
// the hard way.
- SpaceBitmap* object_bitmap = current_mark_bitmap_;
+ accounting::SpaceBitmap* object_bitmap = current_mark_bitmap_;
if (UNLIKELY(!object_bitmap->HasAddress(obj))) {
- SpaceBitmap* new_bitmap = heap_->GetMarkBitmap()->GetSpaceBitmap(obj);
- if (new_bitmap != NULL) {
+ accounting::SpaceBitmap* new_bitmap = heap_->GetMarkBitmap()->GetContinuousSpaceBitmap(obj);
+ if (LIKELY(new_bitmap != NULL)) {
object_bitmap = new_bitmap;
} else {
MarkLargeObject(obj);
@@ -416,13 +395,16 @@ inline void MarkSweep::MarkObjectNonNull(const Object* obj, bool check_finger) {
// Rare case, probably not worth inlining since it will increase instruction cache miss rate.
bool MarkSweep::MarkLargeObject(const Object* obj) {
- LargeObjectSpace* large_object_space = GetHeap()->GetLargeObjectsSpace();
- SpaceSetMap* large_objects = large_object_space->GetMarkObjects();
+ // TODO: support >1 discontinuous space.
+ space::LargeObjectSpace* large_object_space = GetHeap()->GetLargeObjectsSpace();
+ accounting::SpaceSetMap* large_objects = large_object_space->GetMarkObjects();
if (kProfileLargeObjects) {
++large_object_test_;
}
if (UNLIKELY(!large_objects->Test(obj))) {
- if (!large_object_space->Contains(obj)) {
+ // TODO: mark may be called holding the JNI global references lock, Contains will hold the
+ // large object space lock causing a lock level violation. Bug: 9414652;
+ if (!kDebugLocking && !large_object_space->Contains(obj)) {
LOG(ERROR) << "Tried to mark " << obj << " not contained by any spaces";
LOG(ERROR) << "Attempting see if it's a bad root";
VerifyRoots();
@@ -448,9 +430,9 @@ inline bool MarkSweep::MarkObjectParallel(const Object* obj) {
// Try to take advantage of locality of references within a space, failing this find the space
// the hard way.
- SpaceBitmap* object_bitmap = current_mark_bitmap_;
+ accounting::SpaceBitmap* object_bitmap = current_mark_bitmap_;
if (UNLIKELY(!object_bitmap->HasAddress(obj))) {
- SpaceBitmap* new_bitmap = heap_->GetMarkBitmap()->GetSpaceBitmap(obj);
+ accounting::SpaceBitmap* new_bitmap = heap_->GetMarkBitmap()->GetContinuousSpaceBitmap(obj);
if (new_bitmap != NULL) {
object_bitmap = new_bitmap;
} else {
@@ -510,8 +492,8 @@ void MarkSweep::VerifyRootCallback(const Object* root, void* arg, size_t vreg,
void MarkSweep::VerifyRoot(const Object* root, size_t vreg, const StackVisitor* visitor) {
// See if the root is on any space bitmap.
- if (GetHeap()->GetLiveBitmap()->GetSpaceBitmap(root) == NULL) {
- LargeObjectSpace* large_object_space = GetHeap()->GetLargeObjectsSpace();
+ if (GetHeap()->GetLiveBitmap()->GetContinuousSpaceBitmap(root) == NULL) {
+ space::LargeObjectSpace* large_object_space = GetHeap()->GetLargeObjectsSpace();
if (!large_object_space->Contains(root)) {
LOG(ERROR) << "Found invalid root: " << root;
if (visitor != NULL) {
@@ -535,7 +517,8 @@ void MarkSweep::MarkNonThreadRoots() {
}
void MarkSweep::MarkConcurrentRoots() {
- Runtime::Current()->VisitConcurrentRoots(MarkObjectCallback, this);
+ // Visit all runtime roots and clear dirty flags.
+ Runtime::Current()->VisitConcurrentRoots(MarkObjectCallback, this, false, true);
}
class CheckObjectVisitor {
@@ -571,11 +554,11 @@ void MarkSweep::VerifyImageRootVisitor(Object* root, void* arg) {
mark_sweep->CheckObject(root);
}
-void MarkSweep::BindLiveToMarkBitmap(ContinuousSpace* space) {
- CHECK(space->IsAllocSpace());
- DlMallocSpace* alloc_space = space->AsAllocSpace();
- SpaceBitmap* live_bitmap = space->GetLiveBitmap();
- SpaceBitmap* mark_bitmap = alloc_space->mark_bitmap_.release();
+void MarkSweep::BindLiveToMarkBitmap(space::ContinuousSpace* space) {
+ CHECK(space->IsDlMallocSpace());
+ space::DlMallocSpace* alloc_space = space->AsDlMallocSpace();
+ accounting::SpaceBitmap* live_bitmap = space->GetLiveBitmap();
+ accounting::SpaceBitmap* mark_bitmap = alloc_space->mark_bitmap_.release();
GetHeap()->GetMarkBitmap()->ReplaceBitmap(mark_bitmap, live_bitmap);
alloc_space->temp_bitmap_.reset(mark_bitmap);
alloc_space->mark_bitmap_.reset(live_bitmap);
@@ -584,7 +567,6 @@ void MarkSweep::BindLiveToMarkBitmap(ContinuousSpace* space) {
class ScanObjectVisitor {
public:
ScanObjectVisitor(MarkSweep* const mark_sweep) : mark_sweep_(mark_sweep) {
-
}
// TODO: Fixme when anotatalysis works with visitors.
@@ -601,29 +583,39 @@ class ScanObjectVisitor {
};
void MarkSweep::ScanGrayObjects(byte minimum_age) {
- const Spaces& spaces = heap_->GetSpaces();
- CardTable* card_table = heap_->GetCardTable();
+ accounting::CardTable* card_table = GetHeap()->GetCardTable();
+ const std::vector<space::ContinuousSpace*>& spaces = GetHeap()->GetContinuousSpaces();
ScanObjectVisitor visitor(this);
SetFingerVisitor finger_visitor(this);
- // TODO: C++ 0x auto
- for (Spaces::const_iterator it = spaces.begin(); it != spaces.end(); ++it) {
- ContinuousSpace* space = *it;
+ // TODO: C++0x
+ typedef std::vector<space::ContinuousSpace*>::const_iterator It;
+ for (It it = spaces.begin(), space_end = spaces.end(); it != space_end; ++it) {
+ space::ContinuousSpace* space = *it;
+ switch (space->GetGcRetentionPolicy()) {
+ case space::kGcRetentionPolicyNeverCollect:
+ timings_.NewSplit("ScanGrayImageSpaceObjects");
+ break;
+ case space::kGcRetentionPolicyFullCollect:
+ timings_.NewSplit("ScanGrayZygoteSpaceObjects");
+ break;
+ case space::kGcRetentionPolicyAlwaysCollect:
+ timings_.NewSplit("ScanGrayAllocSpaceObjects");
+ break;
+ }
byte* begin = space->Begin();
byte* end = space->End();
// Image spaces are handled properly since live == marked for them.
- SpaceBitmap* mark_bitmap = space->GetMarkBitmap();
- card_table->Scan(mark_bitmap, begin, end, visitor, VoidFunctor(), minimum_age);
+ accounting::SpaceBitmap* mark_bitmap = space->GetMarkBitmap();
+ card_table->Scan(mark_bitmap, begin, end, visitor, finger_visitor, minimum_age);
}
}
class CheckBitmapVisitor {
public:
CheckBitmapVisitor(MarkSweep* mark_sweep) : mark_sweep_(mark_sweep) {
-
}
- void operator ()(const Object* obj) const
- NO_THREAD_SAFETY_ANALYSIS {
+ void operator ()(const Object* obj) const NO_THREAD_SAFETY_ANALYSIS {
if (kDebugLocking) {
Locks::heap_bitmap_lock_->AssertSharedHeld(Thread::Current());
}
@@ -640,13 +632,15 @@ void MarkSweep::VerifyImageRoots() {
// objects which are either in the image space or marked objects in the alloc
// space
CheckBitmapVisitor visitor(this);
- const Spaces& spaces = heap_->GetSpaces();
- for (Spaces::const_iterator it = spaces.begin(); it != spaces.end(); ++it) {
+ const std::vector<space::ContinuousSpace*>& spaces = GetHeap()->GetContinuousSpaces();
+ // TODO: C++0x
+ typedef std::vector<space::ContinuousSpace*>::const_iterator It;
+ for (It it = spaces.begin(), end = spaces.end(); it != end; ++it) {
if ((*it)->IsImageSpace()) {
- ImageSpace* space = (*it)->AsImageSpace();
+ space::ImageSpace* space = (*it)->AsImageSpace();
uintptr_t begin = reinterpret_cast<uintptr_t>(space->Begin());
uintptr_t end = reinterpret_cast<uintptr_t>(space->End());
- SpaceBitmap* live_bitmap = space->GetLiveBitmap();
+ accounting::SpaceBitmap* live_bitmap = space->GetLiveBitmap();
DCHECK(live_bitmap != NULL);
live_bitmap->VisitMarkedRange(begin, end, visitor, VoidFunctor());
}
@@ -656,6 +650,7 @@ void MarkSweep::VerifyImageRoots() {
// Populates the mark stack based on the set of marked objects and
// recursively marks until the mark stack is emptied.
void MarkSweep::RecursiveMark() {
+ timings_.NewSplit("RecursiveMark");
// RecursiveMark will build the lists of known instances of the Reference classes.
// See DelayReferenceReferent for details.
CHECK(soft_reference_list_ == NULL);
@@ -665,16 +660,17 @@ void MarkSweep::RecursiveMark() {
CHECK(cleared_reference_list_ == NULL);
const bool partial = GetGcType() == kGcTypePartial;
- const Spaces& spaces = heap_->GetSpaces();
SetFingerVisitor set_finger_visitor(this);
ScanObjectVisitor scan_visitor(this);
if (!kDisableFinger) {
finger_ = NULL;
- for (Spaces::const_iterator it = spaces.begin(); it != spaces.end(); ++it) {
- ContinuousSpace* space = *it;
- if ((space->GetGcRetentionPolicy() == kGcRetentionPolicyAlwaysCollect) ||
- (!partial && space->GetGcRetentionPolicy() == kGcRetentionPolicyFullCollect)
- ) {
+ const std::vector<space::ContinuousSpace*>& spaces = GetHeap()->GetContinuousSpaces();
+ // TODO: C++0x
+ typedef std::vector<space::ContinuousSpace*>::const_iterator It;
+ for (It it = spaces.begin(), end = spaces.end(); it != end; ++it) {
+ space::ContinuousSpace* space = *it;
+ if ((space->GetGcRetentionPolicy() == space::kGcRetentionPolicyAlwaysCollect) ||
+ (!partial && space->GetGcRetentionPolicy() == space::kGcRetentionPolicyFullCollect)) {
current_mark_bitmap_ = space->GetMarkBitmap();
if (current_mark_bitmap_ == NULL) {
GetHeap()->DumpSpaces();
@@ -688,9 +684,8 @@ void MarkSweep::RecursiveMark() {
}
}
DisableFinger();
- timings_.AddSplit("RecursiveMark");
+ timings_.NewSplit("ProcessMarkStack");
ProcessMarkStack();
- timings_.AddSplit("ProcessMarkStack");
}
bool MarkSweep::IsMarkedCallback(const Object* object, void* arg) {
@@ -701,13 +696,12 @@ bool MarkSweep::IsMarkedCallback(const Object* object, void* arg) {
void MarkSweep::RecursiveMarkDirtyObjects(byte minimum_age) {
ScanGrayObjects(minimum_age);
- timings_.AddSplit("ScanGrayObjects");
+ timings_.NewSplit("ProcessMarkStack");
ProcessMarkStack();
- timings_.AddSplit("ProcessMarkStack");
}
void MarkSweep::ReMarkRoots() {
- Runtime::Current()->VisitRoots(ReMarkObjectVisitor, this);
+ Runtime::Current()->VisitRoots(ReMarkObjectVisitor, this, true, true);
}
void MarkSweep::SweepJniWeakGlobals(IsMarkedTester is_marked, void* arg) {
@@ -724,7 +718,7 @@ void MarkSweep::SweepJniWeakGlobals(IsMarkedTester is_marked, void* arg) {
}
struct ArrayMarkedCheck {
- ObjectStack* live_stack;
+ accounting::ObjectStack* live_stack;
MarkSweep* mark_sweep;
};
@@ -734,11 +728,11 @@ bool MarkSweep::IsMarkedArrayCallback(const Object* object, void* arg) {
if (array_check->mark_sweep->IsMarked(object)) {
return true;
}
- ObjectStack* live_stack = array_check->live_stack;
+ accounting::ObjectStack* live_stack = array_check->live_stack;
return std::find(live_stack->Begin(), live_stack->End(), object) == live_stack->End();
}
-void MarkSweep::SweepSystemWeaksArray(ObjectStack* allocations) {
+void MarkSweep::SweepSystemWeaksArray(accounting::ObjectStack* allocations) {
Runtime* runtime = Runtime::Current();
// The callbacks check
// !is_marked where is_marked is the callback but we want
@@ -775,7 +769,7 @@ bool MarkSweep::VerifyIsLiveCallback(const Object* obj, void* arg) {
void MarkSweep::VerifyIsLive(const Object* obj) {
Heap* heap = GetHeap();
if (!heap->GetLiveBitmap()->Test(obj)) {
- LargeObjectSpace* large_object_space = GetHeap()->GetLargeObjectsSpace();
+ space::LargeObjectSpace* large_object_space = GetHeap()->GetLargeObjectsSpace();
if (!large_object_space->GetLiveObjects()->Test(obj)) {
if (std::find(heap->allocation_stack_->Begin(), heap->allocation_stack_->End(), obj) ==
heap->allocation_stack_->End()) {
@@ -805,7 +799,7 @@ void MarkSweep::VerifySystemWeaks() {
struct SweepCallbackContext {
MarkSweep* mark_sweep;
- AllocSpace* space;
+ space::AllocSpace* space;
Thread* self;
};
@@ -828,28 +822,29 @@ class CheckpointMarkThreadRoots : public Closure {
MarkSweep* mark_sweep_;
};
-void MarkSweep::ResetCumulativeStatistics() {
- cumulative_timings_.Reset();
- total_time_ = 0;
- total_paused_time_ = 0;
- total_freed_objects_ = 0;
- total_freed_bytes_ = 0;
-}
-
-void MarkSweep::MarkRootsCheckpoint() {
+void MarkSweep::MarkRootsCheckpoint(Thread* self) {
CheckpointMarkThreadRoots check_point(this);
ThreadList* thread_list = Runtime::Current()->GetThreadList();
- // Increment the count of the barrier. If all of the checkpoints have already been finished then
- // will hit 0 and continue. Otherwise we are still waiting for some checkpoints, so the counter
- // will go positive and we will unblock when it hits zero.
- gc_barrier_->Increment(Thread::Current(), thread_list->RunCheckpoint(&check_point));
+ // Request the check point is run on all threads returning a count of the threads that must
+ // run through the barrier including self.
+ size_t barrier_count = thread_list->RunCheckpoint(&check_point);
+ // Release locks then wait for all mutator threads to pass the barrier.
+ // TODO: optimize to not release locks when there are no threads to wait for.
+ Locks::heap_bitmap_lock_->ExclusiveUnlock(self);
+ Locks::mutator_lock_->SharedUnlock(self);
+ ThreadState old_state = self->SetState(kWaitingForCheckPointsToRun);
+ CHECK_EQ(old_state, kWaitingPerformingGc);
+ gc_barrier_->Increment(self, barrier_count);
+ self->SetState(kWaitingPerformingGc);
+ Locks::mutator_lock_->SharedLock(self);
+ Locks::heap_bitmap_lock_->ExclusiveLock(self);
}
void MarkSweep::SweepCallback(size_t num_ptrs, Object** ptrs, void* arg) {
SweepCallbackContext* context = static_cast<SweepCallbackContext*>(arg);
MarkSweep* mark_sweep = context->mark_sweep;
Heap* heap = mark_sweep->GetHeap();
- AllocSpace* space = context->space;
+ space::AllocSpace* space = context->space;
Thread* self = context->self;
Locks::heap_bitmap_lock_->AssertExclusiveHeld(self);
// Use a bulk free, that merges consecutive objects before freeing or free per object?
@@ -875,22 +870,23 @@ void MarkSweep::ZygoteSweepCallback(size_t num_ptrs, Object** ptrs, void* arg) {
}
}
-void MarkSweep::SweepArray(TimingLogger& logger, ObjectStack* allocations, bool swap_bitmaps) {
+void MarkSweep::SweepArray(accounting::ObjectStack* allocations, bool swap_bitmaps) {
size_t freed_bytes = 0;
- DlMallocSpace* space = heap_->GetAllocSpace();
+ space::DlMallocSpace* space = heap_->GetAllocSpace();
// If we don't swap bitmaps then newly allocated Weaks go into the live bitmap but not mark
// bitmap, resulting in occasional frees of Weaks which are still in use.
+ timings_.NewSplit("SweepSystemWeaks");
SweepSystemWeaksArray(allocations);
- logger.AddSplit("SweepSystemWeaks");
+ timings_.NewSplit("Process allocation stack");
// Newly allocated objects MUST be in the alloc space and those are the only objects which we are
// going to free.
- SpaceBitmap* live_bitmap = space->GetLiveBitmap();
- SpaceBitmap* mark_bitmap = space->GetMarkBitmap();
- LargeObjectSpace* large_object_space = GetHeap()->GetLargeObjectsSpace();
- SpaceSetMap* large_live_objects = large_object_space->GetLiveObjects();
- SpaceSetMap* large_mark_objects = large_object_space->GetMarkObjects();
+ accounting::SpaceBitmap* live_bitmap = space->GetLiveBitmap();
+ accounting::SpaceBitmap* mark_bitmap = space->GetMarkBitmap();
+ space::LargeObjectSpace* large_object_space = GetHeap()->GetLargeObjectsSpace();
+ accounting::SpaceSetMap* large_live_objects = large_object_space->GetLiveObjects();
+ accounting::SpaceSetMap* large_mark_objects = large_object_space->GetMarkObjects();
if (swap_bitmaps) {
std::swap(live_bitmap, mark_bitmap);
std::swap(large_live_objects, large_mark_objects);
@@ -916,7 +912,8 @@ void MarkSweep::SweepArray(TimingLogger& logger, ObjectStack* allocations, bool
freed_bytes += large_object_space->Free(self, obj);
}
}
- logger.AddSplit("Process allocation stack");
+ CHECK_EQ(count, allocations->Size());
+ timings_.NewSplit("FreeList");
size_t freed_objects = out - objects;
freed_bytes += space->FreeList(self, freed_objects, objects);
@@ -925,71 +922,78 @@ void MarkSweep::SweepArray(TimingLogger& logger, ObjectStack* allocations, bool
heap_->RecordFree(freed_objects + freed_large_objects, freed_bytes);
freed_objects_ += freed_objects;
freed_bytes_ += freed_bytes;
- logger.AddSplit("FreeList");
+
+ timings_.NewSplit("ResetStack");
allocations->Reset();
- logger.AddSplit("ResetStack");
}
-void MarkSweep::Sweep(TimingLogger& timings, bool swap_bitmaps) {
+void MarkSweep::Sweep(bool swap_bitmaps) {
DCHECK(mark_stack_->IsEmpty());
// If we don't swap bitmaps then newly allocated Weaks go into the live bitmap but not mark
// bitmap, resulting in occasional frees of Weaks which are still in use.
+ timings_.NewSplit("SweepSystemWeaks");
SweepSystemWeaks();
- timings.AddSplit("SweepSystemWeaks");
- const bool partial = GetGcType() == kGcTypePartial;
- const Spaces& spaces = heap_->GetSpaces();
+ const bool partial = (GetGcType() == kGcTypePartial);
SweepCallbackContext scc;
scc.mark_sweep = this;
scc.self = Thread::Current();
- // TODO: C++0x auto
- for (Spaces::const_iterator it = spaces.begin(); it != spaces.end(); ++it) {
- ContinuousSpace* space = *it;
- if (
- space->GetGcRetentionPolicy() == kGcRetentionPolicyAlwaysCollect ||
- (!partial && space->GetGcRetentionPolicy() == kGcRetentionPolicyFullCollect)
- ) {
+ const std::vector<space::ContinuousSpace*>& spaces = GetHeap()->GetContinuousSpaces();
+ // TODO: C++0x
+ typedef std::vector<space::ContinuousSpace*>::const_iterator It;
+ for (It it = spaces.begin(), end = spaces.end(); it != end; ++it) {
+ space::ContinuousSpace* space = *it;
+ // We always sweep always collect spaces.
+ bool sweep_space = (space->GetGcRetentionPolicy() == space::kGcRetentionPolicyAlwaysCollect);
+ if (!partial && !sweep_space) {
+ // We sweep full collect spaces when the GC isn't a partial GC (ie its full).
+ sweep_space = (space->GetGcRetentionPolicy() == space::kGcRetentionPolicyFullCollect);
+ }
+ if (sweep_space) {
uintptr_t begin = reinterpret_cast<uintptr_t>(space->Begin());
uintptr_t end = reinterpret_cast<uintptr_t>(space->End());
- scc.space = space->AsAllocSpace();
- SpaceBitmap* live_bitmap = space->GetLiveBitmap();
- SpaceBitmap* mark_bitmap = space->GetMarkBitmap();
+ scc.space = space->AsDlMallocSpace();
+ accounting::SpaceBitmap* live_bitmap = space->GetLiveBitmap();
+ accounting::SpaceBitmap* mark_bitmap = space->GetMarkBitmap();
if (swap_bitmaps) {
std::swap(live_bitmap, mark_bitmap);
}
- if (space->GetGcRetentionPolicy() == kGcRetentionPolicyAlwaysCollect) {
+ if (!space->IsZygoteSpace()) {
+ timings_.NewSplit("SweepAllocSpace");
// Bitmaps are pre-swapped for optimization which enables sweeping with the heap unlocked.
- SpaceBitmap::SweepWalk(*live_bitmap, *mark_bitmap, begin, end,
- &SweepCallback, reinterpret_cast<void*>(&scc));
+ accounting::SpaceBitmap::SweepWalk(*live_bitmap, *mark_bitmap, begin, end,
+ &SweepCallback, reinterpret_cast<void*>(&scc));
} else {
- // Zygote sweep takes care of dirtying cards and clearing live bits, does not free actual memory.
- SpaceBitmap::SweepWalk(*live_bitmap, *mark_bitmap, begin, end,
- &ZygoteSweepCallback, reinterpret_cast<void*>(&scc));
+ timings_.NewSplit("SweepZygote");
+ // Zygote sweep takes care of dirtying cards and clearing live bits, does not free actual
+ // memory.
+ accounting::SpaceBitmap::SweepWalk(*live_bitmap, *mark_bitmap, begin, end,
+ &ZygoteSweepCallback, reinterpret_cast<void*>(&scc));
}
}
}
- timings.AddSplit("Sweep");
+ timings_.NewSplit("SweepLargeObjects");
SweepLargeObjects(swap_bitmaps);
- timings.AddSplit("SweepLargeObjects");
}
void MarkSweep::SweepLargeObjects(bool swap_bitmaps) {
// Sweep large objects
- LargeObjectSpace* large_object_space = GetHeap()->GetLargeObjectsSpace();
- SpaceSetMap* large_live_objects = large_object_space->GetLiveObjects();
- SpaceSetMap* large_mark_objects = large_object_space->GetMarkObjects();
+ space::LargeObjectSpace* large_object_space = GetHeap()->GetLargeObjectsSpace();
+ accounting::SpaceSetMap* large_live_objects = large_object_space->GetLiveObjects();
+ accounting::SpaceSetMap* large_mark_objects = large_object_space->GetMarkObjects();
if (swap_bitmaps) {
std::swap(large_live_objects, large_mark_objects);
}
- SpaceSetMap::Objects& live_objects = large_live_objects->GetObjects();
+ accounting::SpaceSetMap::Objects& live_objects = large_live_objects->GetObjects();
// O(n*log(n)) but hopefully there are not too many large objects.
size_t freed_objects = 0;
size_t freed_bytes = 0;
- // TODO: C++0x
Thread* self = Thread::Current();
- for (SpaceSetMap::Objects::iterator it = live_objects.begin(); it != live_objects.end(); ++it) {
+ // TODO: C++0x
+ typedef accounting::SpaceSetMap::Objects::iterator It;
+ for (It it = live_objects.begin(), end = live_objects.end(); it != end; ++it) {
if (!large_mark_objects->Test(*it)) {
freed_bytes += large_object_space->Free(self, const_cast<Object*>(*it));
++freed_objects;
@@ -997,20 +1001,21 @@ void MarkSweep::SweepLargeObjects(bool swap_bitmaps) {
}
freed_objects_ += freed_objects;
freed_bytes_ += freed_bytes;
- // Large objects don't count towards bytes_allocated.
GetHeap()->RecordFree(freed_objects, freed_bytes);
}
void MarkSweep::CheckReference(const Object* obj, const Object* ref, MemberOffset offset, bool is_static) {
- const Spaces& spaces = heap_->GetSpaces();
- // TODO: C++0x auto
- for (Spaces::const_iterator cur = spaces.begin(); cur != spaces.end(); ++cur) {
- if ((*cur)->IsAllocSpace() && (*cur)->Contains(ref)) {
+ const std::vector<space::ContinuousSpace*>& spaces = GetHeap()->GetContinuousSpaces();
+ // TODO: C++0x
+ typedef std::vector<space::ContinuousSpace*>::const_iterator It;
+ for (It it = spaces.begin(), end = spaces.end(); it != end; ++it) {
+ space::ContinuousSpace* space = *it;
+ if (space->IsDlMallocSpace() && space->Contains(ref)) {
DCHECK(IsMarked(obj));
bool is_marked = IsMarked(ref);
if (!is_marked) {
- LOG(INFO) << **cur;
+ LOG(INFO) << *space;
LOG(WARNING) << (is_static ? "Static ref'" : "Instance ref'") << PrettyTypeOf(ref)
<< "' (" << reinterpret_cast<const void*>(ref) << ") in '" << PrettyTypeOf(obj)
<< "' (" << reinterpret_cast<const void*>(obj) << ") at offset "
@@ -1107,7 +1112,7 @@ void MarkSweep::ScanObject(const Object* obj) {
}
class MarkStackChunk : public Task {
-public:
+ public:
MarkStackChunk(ThreadPool* thread_pool, MarkSweep* mark_sweep, Object** begin, Object** end)
: mark_sweep_(mark_sweep),
thread_pool_(thread_pool),
@@ -1169,6 +1174,7 @@ public:
// Don't need to use atomic ++ since we only one thread is writing to an output block at any
// given time.
void Push(Object* obj) {
+ CHECK(obj != NULL);
data_[length_++] = obj;
}
@@ -1176,7 +1182,7 @@ public:
if (static_cast<size_t>(length_) < max_size) {
Push(const_cast<Object*>(obj));
} else {
- // Internal buffer is full, push to a new buffer instead.
+ // Internal (thread-local) buffer is full, push to a new buffer instead.
if (UNLIKELY(output_ == NULL)) {
AllocateOutputChunk();
} else if (UNLIKELY(static_cast<size_t>(output_->length_) == max_size)) {
@@ -1255,8 +1261,8 @@ void MarkSweep::ProcessMarkStackParallel() {
thread_pool->AddTask(self, new MarkStackChunk(thread_pool, this, begin, end));
}
thread_pool->StartWorkers(self);
+ thread_pool->Wait(self, true, true);
mark_stack_->Reset();
- thread_pool->Wait(self, true);
//LOG(INFO) << "Idle wait time " << PrettyDuration(thread_pool->GetWaitTime());
CHECK_EQ(work_chunks_created_, work_chunks_deleted_) << " some of the work chunks were leaked";
}
@@ -1443,15 +1449,16 @@ void MarkSweep::ProcessReferences(Object** soft_references, bool clear_soft,
}
void MarkSweep::UnBindBitmaps() {
- const Spaces& spaces = heap_->GetSpaces();
- // TODO: C++0x auto
- for (Spaces::const_iterator it = spaces.begin(); it != spaces.end(); ++it) {
- Space* space = *it;
- if (space->IsAllocSpace()) {
- DlMallocSpace* alloc_space = space->AsAllocSpace();
+ const std::vector<space::ContinuousSpace*>& spaces = GetHeap()->GetContinuousSpaces();
+ // TODO: C++0x
+ typedef std::vector<space::ContinuousSpace*>::const_iterator It;
+ for (It it = spaces.begin(), end = spaces.end(); it != end; ++it) {
+ space::ContinuousSpace* space = *it;
+ if (space->IsDlMallocSpace()) {
+ space::DlMallocSpace* alloc_space = space->AsDlMallocSpace();
if (alloc_space->temp_bitmap_.get() != NULL) {
// At this point, the temp_bitmap holds our old mark bitmap.
- SpaceBitmap* new_bitmap = alloc_space->temp_bitmap_.release();
+ accounting::SpaceBitmap* new_bitmap = alloc_space->temp_bitmap_.release();
GetHeap()->GetMarkBitmap()->ReplaceBitmap(alloc_space->mark_bitmap_.get(), new_bitmap);
CHECK_EQ(alloc_space->mark_bitmap_.release(), alloc_space->live_bitmap_.get());
alloc_space->mark_bitmap_.reset(new_bitmap);
@@ -1464,20 +1471,21 @@ void MarkSweep::UnBindBitmaps() {
void MarkSweep::FinishPhase() {
// Can't enqueue referneces if we hold the mutator lock.
Object* cleared_references = GetClearedReferences();
- heap_->EnqueueClearedReferences(&cleared_references);
+ Heap* heap = GetHeap();
+ heap->EnqueueClearedReferences(&cleared_references);
- heap_->PostGcVerification(this);
+ heap->PostGcVerification(this);
- heap_->GrowForUtilization(GetDuration());
- timings_.AddSplit("GrowForUtilization");
+ timings_.NewSplit("GrowForUtilization");
+ heap->GrowForUtilization(GetDurationNs());
- heap_->RequestHeapTrim();
- timings_.AddSplit("RequestHeapTrim");
+ timings_.NewSplit("RequestHeapTrim");
+ heap->RequestHeapTrim();
// Update the cumulative statistics
- total_time_ += GetDuration();
- total_paused_time_ += std::accumulate(GetPauseTimes().begin(), GetPauseTimes().end(), 0,
- std::plus<uint64_t>());
+ total_time_ns_ += GetDurationNs();
+ total_paused_time_ns_ += std::accumulate(GetPauseTimes().begin(), GetPauseTimes().end(), 0,
+ std::plus<uint64_t>());
total_freed_objects_ += GetFreedObjects();
total_freed_bytes_ += GetFreedBytes();
@@ -1511,27 +1519,26 @@ void MarkSweep::FinishPhase() {
// Update the cumulative loggers.
cumulative_timings_.Start();
- cumulative_timings_.AddLogger(timings_);
+ cumulative_timings_.AddNewLogger(timings_);
cumulative_timings_.End();
// Clear all of the spaces' mark bitmaps.
- const Spaces& spaces = heap_->GetSpaces();
- // TODO: C++0x auto
- for (Spaces::const_iterator it = spaces.begin(); it != spaces.end(); ++it) {
- ContinuousSpace* space = *it;
- if (space->GetGcRetentionPolicy() != kGcRetentionPolicyNeverCollect) {
+ const std::vector<space::ContinuousSpace*>& spaces = GetHeap()->GetContinuousSpaces();
+ // TODO: C++0x
+ typedef std::vector<space::ContinuousSpace*>::const_iterator It;
+ for (It it = spaces.begin(), end = spaces.end(); it != end; ++it) {
+ space::ContinuousSpace* space = *it;
+ if (space->GetGcRetentionPolicy() != space::kGcRetentionPolicyNeverCollect) {
space->GetMarkBitmap()->Clear();
}
}
mark_stack_->Reset();
// Reset the marked large objects.
- LargeObjectSpace* large_objects = GetHeap()->GetLargeObjectsSpace();
+ space::LargeObjectSpace* large_objects = GetHeap()->GetLargeObjectsSpace();
large_objects->GetMarkObjects()->Clear();
}
-MarkSweep::~MarkSweep() {
-
-}
-
+} // namespace collector
+} // namespace gc
} // namespace art
diff --git a/src/gc/mark_sweep.h b/src/gc/collector/mark_sweep.h
index 11ce32f59a..9df3c19939 100644
--- a/src/gc/mark_sweep.h
+++ b/src/gc/collector/mark_sweep.h
@@ -21,40 +21,50 @@
#include "barrier.h"
#include "base/macros.h"
#include "base/mutex.h"
-#include "base/timing_logger.h"
#include "garbage_collector.h"
-#include "gc_type.h"
#include "offsets.h"
#include "root_visitor.h"
#include "UniquePtr.h"
namespace art {
+
namespace mirror {
-class Class;
-class Object;
-template<class T> class ObjectArray;
-}
-template <typename T> class AtomicStack;
-class CheckObjectVisitor;
-class ContinuousSpace;
-class Heap;
-class MarkIfReachesAllocspaceVisitor;
-class ModUnionClearCardVisitor;
-class ModUnionVisitor;
-class ModUnionTableBitmap;
-typedef AtomicStack<mirror::Object*> ObjectStack;
-class SpaceBitmap;
+ class Class;
+ class Object;
+ template<class T> class ObjectArray;
+} // namespace mirror
+
class StackVisitor;
class Thread;
-class MarkStackChunk;
+
+namespace gc {
+
+namespace accounting {
+ template <typename T> class AtomicStack;
+ class MarkIfReachesAllocspaceVisitor;
+ class ModUnionClearCardVisitor;
+ class ModUnionVisitor;
+ class ModUnionTableBitmap;
+ class MarkStackChunk;
+ typedef AtomicStack<mirror::Object*> ObjectStack;
+ class SpaceBitmap;
+} // namespace accounting
+
+namespace space {
+ class ContinuousSpace;
+} // namespace space
+
+class CheckObjectVisitor;
+class Heap;
+
+namespace collector {
class MarkSweep : public GarbageCollector {
public:
- explicit MarkSweep(Heap* heap, bool is_concurrent);
+ explicit MarkSweep(Heap* heap, bool is_concurrent, const std::string& name_prefix = "");
- ~MarkSweep();
+ ~MarkSweep() {}
- virtual std::string GetName() const;
virtual void InitializePhase();
virtual bool IsConcurrent() const;
virtual bool HandleDirtyObjectsPhase() EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -85,8 +95,9 @@ class MarkSweep : public GarbageCollector {
void MarkConcurrentRoots();
EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
- void MarkRootsCheckpoint();
- EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
+ void MarkRootsCheckpoint(Thread* self)
+ EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Verify that image roots point to only marked objects within the alloc space.
void VerifyImageRoots()
@@ -98,16 +109,17 @@ class MarkSweep : public GarbageCollector {
EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- // Make a space immune, immune spaces are assumed to have all live objects marked.
- void ImmuneSpace(ContinuousSpace* space)
+ // Make a space immune, immune spaces have all live objects marked - that is the mark and
+ // live bitmaps are bound together.
+ void ImmuneSpace(space::ContinuousSpace* space)
EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- // Bind the live bits to the mark bits of bitmaps based on the gc type.
- virtual void BindBitmaps()
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ // Bind the live bits to the mark bits of bitmaps for spaces that are never collected, ie
+ // the image. Mark that portion of the heap as immune.
+ virtual void BindBitmaps() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- void BindLiveToMarkBitmap(ContinuousSpace* space)
+ void BindLiveToMarkBitmap(space::ContinuousSpace* space)
EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
void UnBindBitmaps()
@@ -127,21 +139,15 @@ class MarkSweep : public GarbageCollector {
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Sweeps unmarked objects to complete the garbage collection.
- virtual void Sweep(TimingLogger& timings, bool swap_bitmaps)
- EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
+ virtual void Sweep(bool swap_bitmaps) EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
// Sweeps unmarked objects to complete the garbage collection.
- void SweepLargeObjects(bool swap_bitmaps)
- EXCLUSIVE_LOCKS_REQUIRED(GlobalSynchronization::heap_bitmap_lock_);
+ void SweepLargeObjects(bool swap_bitmaps) EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
// Sweep only pointers within an array. WARNING: Trashes objects.
- void SweepArray(TimingLogger& logger, ObjectStack* allocation_stack_, bool swap_bitmaps)
+ void SweepArray(accounting::ObjectStack* allocation_stack_, bool swap_bitmaps)
EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
- // Swap bitmaps (if we are a full Gc then we swap the zygote bitmap too).
- virtual void SwapBitmaps() EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
- void SwapLargeObjects() EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
-
mirror::Object* GetClearedReferences() {
return cleared_reference_list_;
}
@@ -177,12 +183,12 @@ class MarkSweep : public GarbageCollector {
return freed_objects_;
}
- uint64_t GetTotalTime() const {
- return total_time_;
+ uint64_t GetTotalTimeNs() const {
+ return total_time_ns_;
}
- uint64_t GetTotalPausedTime() const {
- return total_paused_time_;
+ uint64_t GetTotalPausedTimeNs() const {
+ return total_paused_time_ns_;
}
uint64_t GetTotalFreedObjects() const {
@@ -200,7 +206,7 @@ class MarkSweep : public GarbageCollector {
SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
// Only sweep the weaks which are inside of an allocation stack.
- void SweepSystemWeaksArray(ObjectStack* allocations)
+ void SweepSystemWeaksArray(accounting::ObjectStack* allocations)
SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
static bool VerifyIsLiveCallback(const mirror::Object* obj, void* arg)
@@ -237,16 +243,6 @@ class MarkSweep : public GarbageCollector {
return *gc_barrier_;
}
- TimingLogger& GetTimings() {
- return timings_;
- }
-
- CumulativeLogger& GetCumulativeTimings() {
- return cumulative_timings_;
- }
-
- void ResetCumulativeStatistics();
-
protected:
// Returns true if the object has its bit set in the mark bitmap.
bool IsMarked(const mirror::Object* object) const;
@@ -381,13 +377,14 @@ class MarkSweep : public GarbageCollector {
// Whether or not we count how many of each type of object were scanned.
static const bool kCountScannedTypes = false;
- // Current space, we check this space first to avoid searching for the appropriate space for an object.
- SpaceBitmap* current_mark_bitmap_;
+ // Current space, we check this space first to avoid searching for the appropriate space for an
+ // object.
+ accounting::SpaceBitmap* current_mark_bitmap_;
// Cache java.lang.Class for optimization.
mirror::Class* java_lang_Class_;
- ObjectStack* mark_stack_;
+ accounting::ObjectStack* mark_stack_;
mirror::Object* finger_;
@@ -401,10 +398,15 @@ class MarkSweep : public GarbageCollector {
mirror::Object* phantom_reference_list_;
mirror::Object* cleared_reference_list_;
+ // Number of bytes freed in this collection.
AtomicInteger freed_bytes_;
+ // Number of objects freed in this collection.
AtomicInteger freed_objects_;
+ // Number of classes scanned, if kCountScannedTypes.
AtomicInteger class_count_;
+ // Number of arrays scanned, if kCountScannedTypes.
AtomicInteger array_count_;
+ // Number of non-class/arrays scanned, if kCountScannedTypes.
AtomicInteger other_count_;
AtomicInteger large_object_test_;
AtomicInteger large_object_mark_;
@@ -414,28 +416,19 @@ class MarkSweep : public GarbageCollector {
AtomicInteger work_chunks_deleted_;
AtomicInteger reference_count_;
- // Cumulative statistics.
- uint64_t total_time_;
- uint64_t total_paused_time_;
- uint64_t total_freed_objects_;
- uint64_t total_freed_bytes_;
-
UniquePtr<Barrier> gc_barrier_;
Mutex large_object_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
Mutex mark_stack_expand_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
const bool is_concurrent_;
- TimingLogger timings_;
- CumulativeLogger cumulative_timings_;
-
bool clear_soft_references_;
friend class AddIfReachesAllocSpaceVisitor; // Used by mod-union table.
friend class CheckBitmapVisitor;
friend class CheckObjectVisitor;
friend class CheckReferenceVisitor;
- friend class Heap;
+ friend class art::gc::Heap;
friend class InternTableEntryIsUnmarked;
friend class MarkIfReachesAllocspaceVisitor;
friend class ModUnionCheckReferences;
@@ -453,6 +446,8 @@ class MarkSweep : public GarbageCollector {
DISALLOW_COPY_AND_ASSIGN(MarkSweep);
};
+} // namespace collector
+} // namespace gc
} // namespace art
#endif // ART_SRC_GC_MARK_SWEEP_H_
diff --git a/src/gc/partial_mark_sweep.cc b/src/gc/collector/partial_mark_sweep.cc
index f9c1787045..ef893c50b0 100644
--- a/src/gc/partial_mark_sweep.cc
+++ b/src/gc/collector/partial_mark_sweep.cc
@@ -16,36 +16,38 @@
#include "partial_mark_sweep.h"
-#include "heap.h"
-#include "large_object_space.h"
+#include "gc/heap.h"
+#include "gc/space/space.h"
#include "partial_mark_sweep.h"
-#include "space.h"
#include "thread.h"
namespace art {
+namespace gc {
+namespace collector {
-PartialMarkSweep::PartialMarkSweep(Heap* heap, bool is_concurrent)
- : MarkSweep(heap, is_concurrent) {
+PartialMarkSweep::PartialMarkSweep(Heap* heap, bool is_concurrent, const std::string& name_prefix)
+ : MarkSweep(heap, is_concurrent, name_prefix + (name_prefix.empty() ? "" : " ") + "partial") {
cumulative_timings_.SetName(GetName());
}
-PartialMarkSweep::~PartialMarkSweep() {
-
-}
-
void PartialMarkSweep::BindBitmaps() {
MarkSweep::BindBitmaps();
- Spaces& spaces = GetHeap()->GetSpaces();
+ const std::vector<space::ContinuousSpace*>& spaces = GetHeap()->GetContinuousSpaces();
WriterMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_);
// For partial GCs we need to bind the bitmap of the zygote space so that all objects in the
// zygote space are viewed as marked.
- for (Spaces::iterator it = spaces.begin(); it != spaces.end(); ++it) {
- ContinuousSpace* space = *it;
- if (space->GetGcRetentionPolicy() == kGcRetentionPolicyFullCollect) {
+ // TODO: C++0x
+ typedef std::vector<space::ContinuousSpace*>::const_iterator It;
+ for (It it = spaces.begin(), end = spaces.end(); it != end; ++it) {
+ space::ContinuousSpace* space = *it;
+ if (space->GetGcRetentionPolicy() == space::kGcRetentionPolicyFullCollect) {
+ CHECK(space->IsZygoteSpace());
ImmuneSpace(space);
}
}
}
+} // namespace collector
+} // namespace gc
} // namespace art
diff --git a/src/gc/partial_mark_sweep.h b/src/gc/collector/partial_mark_sweep.h
index 64c0bcd8f8..bd4a580450 100644
--- a/src/gc/partial_mark_sweep.h
+++ b/src/gc/collector/partial_mark_sweep.h
@@ -14,13 +14,15 @@
* limitations under the License.
*/
-#ifndef ART_SRC_GC_PARTIAL_MARK_SWEEP_H_
-#define ART_SRC_GC_PARTIAL_MARK_SWEEP_H_
+#ifndef ART_SRC_GC_COLLECTOR_PARTIAL_MARK_SWEEP_H_
+#define ART_SRC_GC_COLLECTOR_PARTIAL_MARK_SWEEP_H_
#include "locks.h"
#include "mark_sweep.h"
namespace art {
+namespace gc {
+namespace collector {
class PartialMarkSweep : public MarkSweep {
public:
@@ -28,16 +30,19 @@ class PartialMarkSweep : public MarkSweep {
return kGcTypePartial;
}
- explicit PartialMarkSweep(Heap* heap, bool is_concurrent);
- ~PartialMarkSweep();
+ explicit PartialMarkSweep(Heap* heap, bool is_concurrent, const std::string& name_prefix = "");
+ ~PartialMarkSweep() {}
protected:
- virtual void BindBitmaps()
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ // Bind the live bits to the mark bits of bitmaps for spaces that aren't collected for partial
+ // collections, ie the Zygote space. Also mark this space is immune.
+ virtual void BindBitmaps() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
DISALLOW_COPY_AND_ASSIGN(PartialMarkSweep);
};
+} // namespace collector
+} // namespace gc
} // namespace art
-#endif // ART_SRC_GC_PARTIAL_MARK_SWEEP_H_
+#endif // ART_SRC_GC_COLLECTOR_PARTIAL_MARK_SWEEP_H_
diff --git a/src/gc/collector/sticky_mark_sweep.cc b/src/gc/collector/sticky_mark_sweep.cc
new file mode 100644
index 0000000000..71e580d748
--- /dev/null
+++ b/src/gc/collector/sticky_mark_sweep.cc
@@ -0,0 +1,66 @@
+/*
+ * 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 "gc/heap.h"
+#include "gc/space/large_object_space.h"
+#include "gc/space/space.h"
+#include "sticky_mark_sweep.h"
+#include "thread.h"
+
+namespace art {
+namespace gc {
+namespace collector {
+
+StickyMarkSweep::StickyMarkSweep(Heap* heap, bool is_concurrent, const std::string& name_prefix)
+ : PartialMarkSweep(heap, is_concurrent,
+ name_prefix + (name_prefix.empty() ? "" : " ") + "sticky") {
+ cumulative_timings_.SetName(GetName());
+}
+
+void StickyMarkSweep::BindBitmaps() {
+ PartialMarkSweep::BindBitmaps();
+
+ const std::vector<space::ContinuousSpace*>& spaces = GetHeap()->GetContinuousSpaces();
+ WriterMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_);
+ // For sticky GC, we want to bind the bitmaps of all spaces as the allocation stack lets us
+ // know what was allocated since the last GC. A side-effect of binding the allocation space mark
+ // and live bitmap is that marking the objects will place them in the live bitmap.
+ // TODO: C++0x
+ typedef std::vector<space::ContinuousSpace*>::const_iterator It;
+ for (It it = spaces.begin(), end = spaces.end(); it != end; ++it) {
+ space::ContinuousSpace* space = *it;
+ if (space->GetGcRetentionPolicy() == space::kGcRetentionPolicyAlwaysCollect) {
+ BindLiveToMarkBitmap(space);
+ }
+ }
+
+ GetHeap()->GetLargeObjectsSpace()->CopyLiveToMarked();
+}
+
+void StickyMarkSweep::MarkReachableObjects() {
+ DisableFinger();
+ RecursiveMarkDirtyObjects(accounting::CardTable::kCardDirty - 1);
+}
+
+void StickyMarkSweep::Sweep(bool swap_bitmaps) {
+ timings_.NewSplit("SweepArray");
+ accounting::ObjectStack* live_stack = GetHeap()->GetLiveStack();
+ SweepArray(live_stack, false);
+}
+
+} // namespace collector
+} // namespace gc
+} // namespace art
diff --git a/src/gc/sticky_mark_sweep.h b/src/gc/collector/sticky_mark_sweep.h
index 41ab0cc807..b16cfc1b49 100644
--- a/src/gc/sticky_mark_sweep.h
+++ b/src/gc/collector/sticky_mark_sweep.h
@@ -22,29 +22,34 @@
#include "partial_mark_sweep.h"
namespace art {
+namespace gc {
+namespace collector {
class StickyMarkSweep : public PartialMarkSweep {
public:
- virtual GcType GetGcType() const {
+ GcType GetGcType() const {
return kGcTypeSticky;
}
- explicit StickyMarkSweep(Heap* heap, bool is_concurrent);
- ~StickyMarkSweep();
+ explicit StickyMarkSweep(Heap* heap, bool is_concurrent, const std::string& name_prefix = "");
+ ~StickyMarkSweep() {}
+
protected:
- virtual void BindBitmaps()
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ // Bind the live bits to the mark bits of bitmaps for all spaces, all spaces other than the
+ // alloc space will be marked as immune.
+ void BindBitmaps() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- virtual void MarkReachableObjects()
+ void MarkReachableObjects()
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
- virtual void Sweep(TimingLogger& timings, bool swap_bitmaps)
- EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
+ void Sweep(bool swap_bitmaps) EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
DISALLOW_COPY_AND_ASSIGN(StickyMarkSweep);
};
+} // namespace collector
+} // namespace gc
} // namespace art
#endif // ART_SRC_GC_STICKY_MARK_SWEEP_H_
diff --git a/src/gc/garbage_collector.cc b/src/gc/garbage_collector.cc
deleted file mode 100644
index 94daec7c31..0000000000
--- a/src/gc/garbage_collector.cc
+++ /dev/null
@@ -1,87 +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 "garbage_collector.h"
-
-#include "base/mutex-inl.h"
-#include "thread.h"
-#include "thread_list.h"
-
-namespace art {
- GarbageCollector::GarbageCollector(Heap* heap)
- : heap_(heap),
- duration_(0) {
-
- }
-
- bool GarbageCollector::HandleDirtyObjectsPhase() {
- DCHECK(IsConcurrent());
- return true;
- }
-
- void GarbageCollector::RegisterPause(uint64_t nano_length) {
- pause_times_.push_back(nano_length);
- }
-
- void GarbageCollector::Run() {
- Thread* self = Thread::Current();
- ThreadList* thread_list = Runtime::Current()->GetThreadList();
-
- uint64_t start_time = NanoTime();
- pause_times_.clear();
- duration_ = 0;
-
- InitializePhase();
-
- if (!IsConcurrent()) {
- // Pause is the entire length of the GC.
- uint64_t pause_start = NanoTime();
- thread_list->SuspendAll();
- MarkingPhase();
- ReclaimPhase();
- thread_list->ResumeAll();
- uint64_t pause_end = NanoTime();
- pause_times_.push_back(pause_end - pause_start);
- } else {
- {
- ReaderMutexLock mu(self, *Locks::mutator_lock_);
- MarkingPhase();
- }
- bool done = false;
- while (!done) {
- uint64_t pause_start = NanoTime();
- thread_list->SuspendAll();
- done = HandleDirtyObjectsPhase();
- thread_list->ResumeAll();
- uint64_t pause_end = NanoTime();
- pause_times_.push_back(pause_end - pause_start);
- }
- {
- ReaderMutexLock mu(self, *Locks::mutator_lock_);
- ReclaimPhase();
- }
- }
-
- uint64_t end_time = NanoTime();
- duration_ = end_time - start_time;
-
- FinishPhase();
- }
-
- GarbageCollector::~GarbageCollector() {
-
- }
-} // namespace art
diff --git a/src/heap.cc b/src/gc/heap.cc
index f39c26ebde..9ec1f21243 100644
--- a/src/heap.cc
+++ b/src/gc/heap.cc
@@ -16,6 +16,8 @@
#include "heap.h"
+#define ATRACE_TAG ATRACE_TAG_DALVIK
+#include <cutils/trace.h>
#include <sys/types.h>
#include <sys/wait.h>
@@ -25,20 +27,17 @@
#include "base/stl_util.h"
#include "cutils/sched_policy.h"
#include "debugger.h"
-#include "gc/atomic_stack.h"
-#include "gc/card_table.h"
-#include "gc/card_table-inl.h"
-#include "gc/heap_bitmap.h"
-#include "gc/heap_bitmap-inl.h"
-#include "gc/large_object_space.h"
-#include "gc/mark_sweep.h"
-#include "gc/mark_sweep-inl.h"
-#include "gc/partial_mark_sweep.h"
-#include "gc/space_bitmap-inl.h"
-#include "gc/sticky_mark_sweep.h"
-#include "gc/mod_union_table.h"
-#include "gc/mod_union_table-inl.h"
-#include "gc/space.h"
+#include "gc/accounting/atomic_stack.h"
+#include "gc/accounting/card_table-inl.h"
+#include "gc/accounting/heap_bitmap-inl.h"
+#include "gc/accounting/mod_union_table-inl.h"
+#include "gc/accounting/space_bitmap-inl.h"
+#include "gc/collector/mark_sweep-inl.h"
+#include "gc/collector/partial_mark_sweep.h"
+#include "gc/collector/sticky_mark_sweep.h"
+#include "gc/space/image_space.h"
+#include "gc/space/large_object_space.h"
+#include "gc/space/space-inl.h"
#include "image.h"
#include "invoke_arg_array_builder.h"
#include "mirror/class-inl.h"
@@ -56,10 +55,15 @@
#include "well_known_classes.h"
namespace art {
+namespace gc {
+// When to create a log message about a slow GC, 100ms.
static const uint64_t kSlowGcThreshold = MsToNs(100);
+// When to create a log message about a slow pause, 5ms.
static const uint64_t kLongGcPauseThreshold = MsToNs(5);
static const bool kDumpGcPerformanceOnShutdown = false;
+// Minimum amount of remaining bytes before a concurrent GC is triggered.
+static const size_t kMinConcurrentRemainingBytes = 128 * KB;
const double Heap::kDefaultTargetUtilization = 0.5;
static bool GenerateImage(const std::string& image_file_name) {
@@ -156,19 +160,18 @@ Heap::Heap(size_t initial_size, size_t growth_limit, size_t min_free, size_t max
card_table_(NULL),
concurrent_gc_(concurrent_gc),
have_zygote_space_(false),
+ reference_queue_lock_(NULL),
is_gc_running_(false),
- last_gc_type_(kGcTypeNone),
- enforce_heap_growth_rate_(false),
+ last_gc_type_(collector::kGcTypeNone),
capacity_(capacity),
growth_limit_(growth_limit),
max_allowed_footprint_(initial_size),
- concurrent_start_size_(128 * KB),
- concurrent_min_free_(256 * KB),
- concurrent_start_bytes_(concurrent_gc ? initial_size - concurrent_start_size_ :
- std::numeric_limits<size_t>::max()),
+ concurrent_start_bytes_(concurrent_gc ? initial_size - (kMinConcurrentRemainingBytes)
+ : std::numeric_limits<size_t>::max()),
sticky_gc_count_(0),
- total_bytes_freed_(0),
- total_objects_freed_(0),
+ sticky_to_partial_gc_ratio_(10),
+ total_bytes_freed_ever_(0),
+ total_objects_freed_ever_(0),
large_object_threshold_(3 * kPageSize),
num_bytes_allocated_(0),
verify_missing_card_marks_(false),
@@ -176,12 +179,11 @@ Heap::Heap(size_t initial_size, size_t growth_limit, size_t min_free, size_t max
verify_pre_gc_heap_(false),
verify_post_gc_heap_(false),
verify_mod_union_table_(false),
- partial_gc_frequency_(10),
min_alloc_space_size_for_sticky_gc_(2 * MB),
min_remaining_space_for_sticky_gc_(1 * MB),
- last_trim_time_(0),
+ last_trim_time_ms_(0),
allocation_rate_(0),
- max_allocation_stack_size_(MB),
+ max_allocation_stack_size_(kDesiredHeapVerification > kNoHeapVerification? KB : MB),
reference_referent_offset_(0),
reference_queue_offset_(0),
reference_queueNext_offset_(0),
@@ -198,34 +200,34 @@ Heap::Heap(size_t initial_size, size_t growth_limit, size_t min_free, size_t max
LOG(INFO) << "Heap() entering";
}
- live_bitmap_.reset(new HeapBitmap(this));
- mark_bitmap_.reset(new HeapBitmap(this));
+ live_bitmap_.reset(new accounting::HeapBitmap(this));
+ mark_bitmap_.reset(new accounting::HeapBitmap(this));
// Requested begin for the alloc space, to follow the mapped image and oat files
byte* requested_begin = NULL;
std::string image_file_name(original_image_file_name);
if (!image_file_name.empty()) {
- ImageSpace* image_space = NULL;
+ space::ImageSpace* image_space = NULL;
if (OS::FileExists(image_file_name.c_str())) {
// If the /system file exists, it should be up-to-date, don't try to generate
- image_space = ImageSpace::Create(image_file_name);
+ image_space = space::ImageSpace::Create(image_file_name);
} else {
// If the /system file didn't exist, we need to use one from the dalvik-cache.
// If the cache file exists, try to open, but if it fails, regenerate.
// If it does not exist, generate.
image_file_name = GetDalvikCacheFilenameOrDie(image_file_name);
if (OS::FileExists(image_file_name.c_str())) {
- image_space = ImageSpace::Create(image_file_name);
+ image_space = space::ImageSpace::Create(image_file_name);
}
if (image_space == NULL) {
CHECK(GenerateImage(image_file_name)) << "Failed to generate image: " << image_file_name;
- image_space = ImageSpace::Create(image_file_name);
+ image_space = space::ImageSpace::Create(image_file_name);
}
}
CHECK(image_space != NULL) << "Failed to create space from " << image_file_name;
- AddSpace(image_space);
+ AddContinuousSpace(image_space);
// Oat files referenced by image files immediately follow them in memory, ensure alloc space
// isn't going to get in the middle
byte* oat_file_end_addr = image_space->GetImageHeader().GetOatFileEnd();
@@ -247,46 +249,47 @@ Heap::Heap(size_t initial_size, size_t growth_limit, size_t min_free, size_t max
// Allocate the large object space.
const bool kUseFreeListSpaceForLOS = false;
if (kUseFreeListSpaceForLOS) {
- large_object_space_.reset(FreeListSpace::Create("large object space", NULL, capacity));
+ large_object_space_ = space::FreeListSpace::Create("large object space", NULL, capacity);
} else {
- large_object_space_.reset(LargeObjectMapSpace::Create("large object space"));
+ large_object_space_ = space::LargeObjectMapSpace::Create("large object space");
}
- live_bitmap_->SetLargeObjects(large_object_space_->GetLiveObjects());
- mark_bitmap_->SetLargeObjects(large_object_space_->GetMarkObjects());
+ CHECK(large_object_space_ != NULL) << "Failed to create large object space";
+ AddDiscontinuousSpace(large_object_space_);
- UniquePtr<DlMallocSpace> alloc_space(DlMallocSpace::Create("alloc space", initial_size,
- growth_limit, capacity,
- requested_begin));
- alloc_space_ = alloc_space.release();
+ alloc_space_ = space::DlMallocSpace::Create("alloc space",
+ initial_size,
+ growth_limit, capacity,
+ requested_begin);
CHECK(alloc_space_ != NULL) << "Failed to create alloc space";
alloc_space_->SetFootprintLimit(alloc_space_->Capacity());
- AddSpace(alloc_space_);
+ AddContinuousSpace(alloc_space_);
- // Spaces are sorted in order of Begin().
- byte* heap_begin = spaces_.front()->Begin();
- size_t heap_capacity = spaces_.back()->End() - spaces_.front()->Begin();
- if (spaces_.back()->IsAllocSpace()) {
- heap_capacity += spaces_.back()->AsAllocSpace()->NonGrowthLimitCapacity();
+ // Compute heap capacity. Continuous spaces are sorted in order of Begin().
+ byte* heap_begin = continuous_spaces_.front()->Begin();
+ size_t heap_capacity = continuous_spaces_.back()->End() - continuous_spaces_.front()->Begin();
+ if (continuous_spaces_.back()->IsDlMallocSpace()) {
+ heap_capacity += continuous_spaces_.back()->AsDlMallocSpace()->NonGrowthLimitCapacity();
}
// Mark image objects in the live bitmap
// TODO: C++0x
- for (Spaces::iterator it = spaces_.begin(); it != spaces_.end(); ++it) {
- Space* space = *it;
+ typedef std::vector<space::ContinuousSpace*>::iterator It;
+ for (It it = continuous_spaces_.begin(); it != continuous_spaces_.end(); ++it) {
+ space::ContinuousSpace* space = *it;
if (space->IsImageSpace()) {
- ImageSpace* image_space = space->AsImageSpace();
+ space::ImageSpace* image_space = space->AsImageSpace();
image_space->RecordImageAllocations(image_space->GetLiveBitmap());
}
}
// Allocate the card table.
- card_table_.reset(CardTable::Create(heap_begin, heap_capacity));
+ card_table_.reset(accounting::CardTable::Create(heap_begin, heap_capacity));
CHECK(card_table_.get() != NULL) << "Failed to create card table";
- mod_union_table_.reset(new ModUnionTableToZygoteAllocspace<ModUnionTableReferenceCache>(this));
- CHECK(mod_union_table_.get() != NULL) << "Failed to create mod-union table";
+ image_mod_union_table_.reset(new accounting::ModUnionTableToZygoteAllocspace(this));
+ CHECK(image_mod_union_table_.get() != NULL) << "Failed to create image mod-union table";
- zygote_mod_union_table_.reset(new ModUnionTableCardCache(this));
+ zygote_mod_union_table_.reset(new accounting::ModUnionTableCardCache(this));
CHECK(zygote_mod_union_table_.get() != NULL) << "Failed to create Zygote mod-union table";
// TODO: Count objects in the image space here.
@@ -294,11 +297,11 @@ Heap::Heap(size_t initial_size, size_t growth_limit, size_t min_free, size_t max
// Default mark stack size in bytes.
static const size_t default_mark_stack_size = 64 * KB;
- mark_stack_.reset(ObjectStack::Create("mark stack", default_mark_stack_size));
- allocation_stack_.reset(ObjectStack::Create("allocation stack",
- max_allocation_stack_size_));
- live_stack_.reset(ObjectStack::Create("live stack",
- max_allocation_stack_size_));
+ mark_stack_.reset(accounting::ObjectStack::Create("mark stack", default_mark_stack_size));
+ allocation_stack_.reset(accounting::ObjectStack::Create("allocation stack",
+ max_allocation_stack_size_));
+ live_stack_.reset(accounting::ObjectStack::Create("live stack",
+ max_allocation_stack_size_));
// It's still too early to take a lock because there are no threads yet, but we can create locks
// now. We don't create it earlier to make it clear that you can't use locks during heap
@@ -308,17 +311,17 @@ Heap::Heap(size_t initial_size, size_t growth_limit, size_t min_free, size_t max
*gc_complete_lock_));
// Create the reference queue lock, this is required so for parrallel object scanning in the GC.
- reference_queue_lock_.reset(new Mutex("reference queue lock"));
+ reference_queue_lock_ = new Mutex("reference queue lock");
- last_gc_time_ = NanoTime();
+ last_gc_time_ns_ = NanoTime();
last_gc_size_ = GetBytesAllocated();
// Create our garbage collectors.
for (size_t i = 0; i < 2; ++i) {
const bool concurrent = i != 0;
- mark_sweep_collectors_.push_back(new MarkSweep(this, concurrent));
- mark_sweep_collectors_.push_back(new PartialMarkSweep(this, concurrent));
- mark_sweep_collectors_.push_back(new StickyMarkSweep(this, concurrent));
+ mark_sweep_collectors_.push_back(new collector::MarkSweep(this, concurrent));
+ mark_sweep_collectors_.push_back(new collector::PartialMarkSweep(this, concurrent));
+ mark_sweep_collectors_.push_back(new collector::StickyMarkSweep(this, concurrent));
}
CHECK(max_allowed_footprint_ != 0);
@@ -331,7 +334,7 @@ void Heap::CreateThreadPool() {
// TODO: Make sysconf(_SC_NPROCESSORS_CONF) be a helper function?
// Use the number of processors - 1 since the thread doing the GC does work while its waiting for
// workers to complete.
- thread_pool_.reset(new ThreadPool(sysconf(_SC_NPROCESSORS_CONF) - 1));
+ thread_pool_.reset(new ThreadPool(1)); // new ThreadPool(sysconf(_SC_NPROCESSORS_CONF) - 1));
}
void Heap::DeleteThreadPool() {
@@ -339,44 +342,55 @@ void Heap::DeleteThreadPool() {
}
// Sort spaces based on begin address
-struct SpaceSorter {
- bool operator ()(const ContinuousSpace* a, const ContinuousSpace* b) const {
+struct ContinuousSpaceSorter {
+ bool operator ()(const space::ContinuousSpace* a, const space::ContinuousSpace* b) const {
return a->Begin() < b->Begin();
}
};
-void Heap::AddSpace(ContinuousSpace* space) {
+void Heap::AddContinuousSpace(space::ContinuousSpace* space) {
WriterMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_);
DCHECK(space != NULL);
DCHECK(space->GetLiveBitmap() != NULL);
- live_bitmap_->AddSpaceBitmap(space->GetLiveBitmap());
+ live_bitmap_->AddContinuousSpaceBitmap(space->GetLiveBitmap());
DCHECK(space->GetMarkBitmap() != NULL);
- mark_bitmap_->AddSpaceBitmap(space->GetMarkBitmap());
- spaces_.push_back(space);
- if (space->IsAllocSpace()) {
- alloc_space_ = space->AsAllocSpace();
+ mark_bitmap_->AddContinuousSpaceBitmap(space->GetMarkBitmap());
+ continuous_spaces_.push_back(space);
+ if (space->IsDlMallocSpace() && !space->IsLargeObjectSpace()) {
+ alloc_space_ = space->AsDlMallocSpace();
}
// Ensure that spaces remain sorted in increasing order of start address (required for CMS finger)
- std::sort(spaces_.begin(), spaces_.end(), SpaceSorter());
+ std::sort(continuous_spaces_.begin(), continuous_spaces_.end(), ContinuousSpaceSorter());
// Ensure that ImageSpaces < ZygoteSpaces < AllocSpaces so that we can do address based checks to
// avoid redundant marking.
bool seen_zygote = false, seen_alloc = false;
- for (Spaces::const_iterator it = spaces_.begin(); it != spaces_.end(); ++it) {
- Space* space = *it;
+ typedef std::vector<space::ContinuousSpace*>::const_iterator It;
+ for (It it = continuous_spaces_.begin(); it != continuous_spaces_.end(); ++it) {
+ space::ContinuousSpace* space = *it;
if (space->IsImageSpace()) {
DCHECK(!seen_zygote);
DCHECK(!seen_alloc);
} else if (space->IsZygoteSpace()) {
DCHECK(!seen_alloc);
seen_zygote = true;
- } else if (space->IsAllocSpace()) {
+ } else if (space->IsDlMallocSpace()) {
seen_alloc = true;
}
}
}
+void Heap::AddDiscontinuousSpace(space::DiscontinuousSpace* space) {
+ WriterMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_);
+ DCHECK(space != NULL);
+ DCHECK(space->GetLiveObjects() != NULL);
+ live_bitmap_->AddDiscontinuousObjectSet(space->GetLiveObjects());
+ DCHECK(space->GetMarkObjects() != NULL);
+ mark_bitmap_->AddDiscontinuousObjectSet(space->GetMarkObjects());
+ discontinuous_spaces_.push_back(space);
+}
+
void Heap::DumpGcPerformanceInfo(std::ostream& os) {
// Dump cumulative timings.
os << "Dumping cumulative Gc timings\n";
@@ -385,14 +399,15 @@ void Heap::DumpGcPerformanceInfo(std::ostream& os) {
// Dump cumulative loggers for each GC type.
// TODO: C++0x
uint64_t total_paused_time = 0;
- for (Collectors::const_iterator it = mark_sweep_collectors_.begin();
+ typedef std::vector<collector::MarkSweep*>::const_iterator It;
+ for (It it = mark_sweep_collectors_.begin();
it != mark_sweep_collectors_.end(); ++it) {
- MarkSweep* collector = *it;
+ collector::MarkSweep* collector = *it;
CumulativeLogger& logger = collector->GetCumulativeTimings();
if (logger.GetTotalNs() != 0) {
os << Dumpable<CumulativeLogger>(logger);
const uint64_t total_ns = logger.GetTotalNs();
- const uint64_t total_pause_ns = (*it)->GetTotalPausedTime();
+ const uint64_t total_pause_ns = (*it)->GetTotalPausedTimeNs();
double seconds = NsToMs(logger.GetTotalNs()) / 1000.0;
const uint64_t freed_bytes = collector->GetTotalFreedBytes();
const uint64_t freed_objects = collector->GetTotalFreedObjects();
@@ -407,15 +422,15 @@ void Heap::DumpGcPerformanceInfo(std::ostream& os) {
}
}
uint64_t allocation_time = static_cast<uint64_t>(total_allocation_time_) * kTimeAdjust;
- size_t total_objects_allocated = GetTotalObjectsAllocated();
- size_t total_bytes_allocated = GetTotalBytesAllocated();
+ size_t total_objects_allocated = GetObjectsAllocatedEver();
+ size_t total_bytes_allocated = GetBytesAllocatedEver();
if (total_duration != 0) {
const double total_seconds = double(total_duration / 1000) / 1000000.0;
os << "Total time spent in GC: " << PrettyDuration(total_duration) << "\n";
os << "Mean GC size throughput: "
- << PrettySize(GetTotalBytesFreed() / total_seconds) << "/s\n";
+ << PrettySize(GetBytesFreedEver() / total_seconds) << "/s\n";
os << "Mean GC object throughput: "
- << (GetTotalObjectsFreed() / total_seconds) << " objects/s\n";
+ << (GetObjectsFreedEver() / total_seconds) << " objects/s\n";
}
os << "Total number of allocations: " << total_objects_allocated << "\n";
os << "Total bytes allocated " << PrettySize(total_bytes_allocated) << "\n";
@@ -444,33 +459,59 @@ Heap::~Heap() {
// heap lock held. We know though that no non-daemon threads are executing, and we know that
// all daemon threads are suspended, and we also know that the threads list have been deleted, so
// those threads can't resume. We're the only running thread, and we can do whatever we like...
- STLDeleteElements(&spaces_);
+ STLDeleteElements(&continuous_spaces_);
+ STLDeleteElements(&discontinuous_spaces_);
delete gc_complete_lock_;
+ delete reference_queue_lock_;
}
-ContinuousSpace* Heap::FindSpaceFromObject(const mirror::Object* obj) const {
+space::ContinuousSpace* Heap::FindContinuousSpaceFromObject(const mirror::Object* obj,
+ bool fail_ok) const {
// TODO: C++0x auto
- for (Spaces::const_iterator it = spaces_.begin(); it != spaces_.end(); ++it) {
+ typedef std::vector<space::ContinuousSpace*>::const_iterator It;
+ for (It it = continuous_spaces_.begin(), end = continuous_spaces_.end(); it != end; ++it) {
if ((*it)->Contains(obj)) {
return *it;
}
}
- LOG(FATAL) << "object " << reinterpret_cast<const void*>(obj) << " not inside any spaces!";
+ if (!fail_ok) {
+ LOG(FATAL) << "object " << reinterpret_cast<const void*>(obj) << " not inside any spaces!";
+ }
return NULL;
}
-ImageSpace* Heap::GetImageSpace() {
+space::DiscontinuousSpace* Heap::FindDiscontinuousSpaceFromObject(const mirror::Object* obj,
+ bool fail_ok) const {
// TODO: C++0x auto
- for (Spaces::const_iterator it = spaces_.begin(); it != spaces_.end(); ++it) {
- if ((*it)->IsImageSpace()) {
- return (*it)->AsImageSpace();
+ typedef std::vector<space::DiscontinuousSpace*>::const_iterator It;
+ for (It it = discontinuous_spaces_.begin(), end = discontinuous_spaces_.end(); it != end; ++it) {
+ if ((*it)->Contains(obj)) {
+ return *it;
}
}
+ if (!fail_ok) {
+ LOG(FATAL) << "object " << reinterpret_cast<const void*>(obj) << " not inside any spaces!";
+ }
return NULL;
}
-DlMallocSpace* Heap::GetAllocSpace() {
- return alloc_space_;
+space::Space* Heap::FindSpaceFromObject(const mirror::Object* obj, bool fail_ok) const {
+ space::Space* result = FindContinuousSpaceFromObject(obj, true);
+ if (result != NULL) {
+ return result;
+ }
+ return FindDiscontinuousSpaceFromObject(obj, true);
+}
+
+space::ImageSpace* Heap::GetImageSpace() const {
+ // TODO: C++0x auto
+ typedef std::vector<space::ContinuousSpace*>::const_iterator It;
+ for (It it = continuous_spaces_.begin(), end = continuous_spaces_.end(); it != end; ++it) {
+ if ((*it)->IsImageSpace()) {
+ return (*it)->AsImageSpace();
+ }
+ }
+ return NULL;
}
static void MSpaceChunkCallback(void* start, void* end, size_t used_bytes, void* arg) {
@@ -501,17 +542,17 @@ mirror::Object* Heap::AllocObject(Thread* self, mirror::Class* c, size_t byte_co
// range. This also means that we rely on SetClass not dirtying the object's card.
if (byte_count >= large_object_threshold_ && have_zygote_space_ && c->IsPrimitiveArray()) {
size = RoundUp(byte_count, kPageSize);
- obj = Allocate(self, large_object_space_.get(), size);
+ obj = Allocate(self, large_object_space_, size);
// Make sure that our large object didn't get placed anywhere within the space interval or else
// it breaks the immune range.
DCHECK(obj == NULL ||
- reinterpret_cast<byte*>(obj) < spaces_.front()->Begin() ||
- reinterpret_cast<byte*>(obj) >= spaces_.back()->End());
+ reinterpret_cast<byte*>(obj) < continuous_spaces_.front()->Begin() ||
+ reinterpret_cast<byte*>(obj) >= continuous_spaces_.back()->End());
} else {
obj = Allocate(self, alloc_space_, byte_count);
// Ensure that we did not allocate into a zygote space.
- DCHECK(obj == NULL || !have_zygote_space_ || !FindSpaceFromObject(obj)->IsZygoteSpace());
+ DCHECK(obj == NULL || !have_zygote_space_ || !FindSpaceFromObject(obj, false)->IsZygoteSpace());
size = alloc_space_->AllocationSize(obj);
}
@@ -543,8 +584,8 @@ mirror::Object* Heap::AllocObject(Thread* self, mirror::Class* c, size_t byte_co
}
std::ostringstream oss;
int64_t total_bytes_free = GetFreeMemory();
- uint64_t alloc_space_size = alloc_space_->GetNumBytesAllocated();
- uint64_t large_object_size = large_object_space_->GetNumObjectsAllocated();
+ uint64_t alloc_space_size = alloc_space_->GetBytesAllocated();
+ uint64_t large_object_size = large_object_space_->GetObjectsAllocated();
oss << "Failed to allocate a " << byte_count << " byte allocation with " << total_bytes_free
<< " free bytes; allocation space size " << alloc_space_size
<< "; large object space size " << large_object_size;
@@ -552,9 +593,11 @@ mirror::Object* Heap::AllocObject(Thread* self, mirror::Class* c, size_t byte_co
if (total_bytes_free >= byte_count) {
size_t max_contiguous_allocation = 0;
// TODO: C++0x auto
- for (Spaces::const_iterator it = spaces_.begin(); it != spaces_.end(); ++it) {
- if ((*it)->IsAllocSpace()) {
- (*it)->AsAllocSpace()->Walk(MSpaceChunkCallback, &max_contiguous_allocation);
+ typedef std::vector<space::ContinuousSpace*>::const_iterator It;
+ for (It it = continuous_spaces_.begin(), end = continuous_spaces_.end(); it != end; ++it) {
+ space::ContinuousSpace* space = *it;
+ if (space->IsDlMallocSpace()) {
+ space->AsDlMallocSpace()->Walk(MSpaceChunkCallback, &max_contiguous_allocation);
}
}
oss << "; failed due to fragmentation (largest possible contiguous allocation "
@@ -570,20 +613,41 @@ bool Heap::IsHeapAddress(const mirror::Object* obj) {
if (obj == NULL) {
return true;
}
- if (!IsAligned<kObjectAlignment>(obj)) {
+ if (UNLIKELY(!IsAligned<kObjectAlignment>(obj))) {
return false;
}
- for (size_t i = 0; i < spaces_.size(); ++i) {
- if (spaces_[i]->Contains(obj)) {
- return true;
- }
- }
- return large_object_space_->Contains(obj);
+ return FindSpaceFromObject(obj, true) != NULL;
}
bool Heap::IsLiveObjectLocked(const mirror::Object* obj) {
- Locks::heap_bitmap_lock_->AssertReaderHeld(Thread::Current());
- return IsHeapAddress(obj) && GetLiveBitmap()->Test(obj);
+ //Locks::heap_bitmap_lock_->AssertReaderHeld(Thread::Current());
+ if (obj == NULL) {
+ return false;
+ }
+ if (UNLIKELY(!IsAligned<kObjectAlignment>(obj))) {
+ return false;
+ }
+ space::ContinuousSpace* cont_space = FindContinuousSpaceFromObject(obj, true);
+ if (cont_space != NULL) {
+ if (cont_space->GetLiveBitmap()->Test(obj)) {
+ return true;
+ }
+ } else {
+ space::DiscontinuousSpace* disc_space = FindDiscontinuousSpaceFromObject(obj, true);
+ if (disc_space != NULL) {
+ if (disc_space->GetLiveObjects()->Test(obj)) {
+ return true;
+ }
+ }
+ }
+ for (size_t i = 0; i < 5; ++i) {
+ if (allocation_stack_->Contains(const_cast<mirror::Object*>(obj)) ||
+ live_stack_->Contains(const_cast<mirror::Object*>(obj))) {
+ return true;
+ }
+ NanoSleep(MsToNs(10));
+ }
+ return false;
}
void Heap::VerifyObjectImpl(const mirror::Object* obj) {
@@ -596,16 +660,19 @@ void Heap::VerifyObjectImpl(const mirror::Object* obj) {
void Heap::DumpSpaces() {
// TODO: C++0x auto
- for (Spaces::iterator it = spaces_.begin(); it != spaces_.end(); ++it) {
- ContinuousSpace* space = *it;
- SpaceBitmap* live_bitmap = space->GetLiveBitmap();
- SpaceBitmap* mark_bitmap = space->GetMarkBitmap();
+ typedef std::vector<space::ContinuousSpace*>::const_iterator It;
+ for (It it = continuous_spaces_.begin(), end = continuous_spaces_.end(); it != end; ++it) {
+ space::ContinuousSpace* space = *it;
+ accounting::SpaceBitmap* live_bitmap = space->GetLiveBitmap();
+ accounting::SpaceBitmap* mark_bitmap = space->GetMarkBitmap();
LOG(INFO) << space << " " << *space << "\n"
<< live_bitmap << " " << *live_bitmap << "\n"
<< mark_bitmap << " " << *mark_bitmap;
}
- if (large_object_space_.get() != NULL) {
- large_object_space_->Dump(LOG(INFO));
+ typedef std::vector<space::DiscontinuousSpace*>::const_iterator It2;
+ for (It2 it = discontinuous_spaces_.begin(), end = discontinuous_spaces_.end(); it != end; ++it) {
+ space::DiscontinuousSpace* space = *it;
+ LOG(INFO) << space << " " << *space << "\n";
}
}
@@ -636,18 +703,11 @@ void Heap::VerifyObjectBody(const mirror::Object* obj) {
if (verify_object_mode_ != kVerifyAllFast) {
// TODO: the bitmap tests below are racy if VerifyObjectBody is called without the
// heap_bitmap_lock_.
- if (!GetLiveBitmap()->Test(obj)) {
- // Check the allocation stack / live stack.
- if (!std::binary_search(live_stack_->Begin(), live_stack_->End(), obj) &&
- std::find(allocation_stack_->Begin(), allocation_stack_->End(), obj) ==
- allocation_stack_->End()) {
- if (large_object_space_->GetLiveObjects()->Test(obj)) {
- DumpSpaces();
- LOG(FATAL) << "Object is dead: " << obj;
- }
- }
+ if (!IsLiveObjectLocked(obj)) {
+ DumpSpaces();
+ LOG(FATAL) << "Object is dead: " << obj;
}
- if (!GetLiveBitmap()->Test(c)) {
+ if (!IsLiveObjectLocked(c)) {
LOG(FATAL) << "Class of object is dead: " << c << " in object: " << obj;
}
}
@@ -682,7 +742,7 @@ void Heap::RecordAllocation(size_t size, mirror::Object* obj) {
// This is safe to do since the GC will never free objects which are neither in the allocation
// stack or the live bitmap.
while (!allocation_stack_->AtomicPushBack(obj)) {
- CollectGarbageInternal(kGcTypeSticky, kGcCauseForAlloc, false);
+ CollectGarbageInternal(collector::kGcTypeSticky, kGcCauseForAlloc, false);
}
}
@@ -702,7 +762,8 @@ void Heap::RecordFree(size_t freed_objects, size_t freed_bytes) {
}
}
-mirror::Object* Heap::TryToAllocate(Thread* self, AllocSpace* space, size_t alloc_size, bool grow) {
+mirror::Object* Heap::TryToAllocate(Thread* self, space::AllocSpace* space, size_t alloc_size,
+ bool grow) {
// Should we try to use a CAS here and fix up num_bytes_allocated_ later with AllocationSize?
if (num_bytes_allocated_ + alloc_size > max_allowed_footprint_) {
// max_allowed_footprint_ <= growth_limit_ so it is safe to check in here.
@@ -710,23 +771,12 @@ mirror::Object* Heap::TryToAllocate(Thread* self, AllocSpace* space, size_t allo
// Completely out of memory.
return NULL;
}
-
- if (enforce_heap_growth_rate_) {
- if (grow) {
- // Grow the heap by alloc_size extra bytes.
- max_allowed_footprint_ = std::min(max_allowed_footprint_ + alloc_size, growth_limit_);
- VLOG(gc) << "Grow heap to " << PrettySize(max_allowed_footprint_)
- << " for a " << PrettySize(alloc_size) << " allocation";
- } else {
- return NULL;
- }
- }
}
return space->Alloc(self, alloc_size);
}
-mirror::Object* Heap::Allocate(Thread* self, AllocSpace* space, size_t alloc_size) {
+mirror::Object* Heap::Allocate(Thread* self, space::AllocSpace* space, size_t alloc_size) {
// Since allocation can cause a GC which will need to SuspendAll, make sure all allocations are
// done in the runnable state where suspension is expected.
DCHECK_EQ(self->GetState(), kRunnable);
@@ -739,8 +789,8 @@ mirror::Object* Heap::Allocate(Thread* self, AllocSpace* space, size_t alloc_siz
// The allocation failed. If the GC is running, block until it completes, and then retry the
// allocation.
- GcType last_gc = WaitForConcurrentGcToComplete(self);
- if (last_gc != kGcTypeNone) {
+ collector::GcType last_gc = WaitForConcurrentGcToComplete(self);
+ if (last_gc != collector::kGcTypeNone) {
// A GC was in progress and we blocked, retry allocation now that memory has been freed.
ptr = TryToAllocate(self, space, alloc_size, false);
if (ptr != NULL) {
@@ -749,20 +799,21 @@ mirror::Object* Heap::Allocate(Thread* self, AllocSpace* space, size_t alloc_siz
}
// Loop through our different Gc types and try to Gc until we get enough free memory.
- for (size_t i = static_cast<size_t>(last_gc) + 1; i < static_cast<size_t>(kGcTypeMax); ++i) {
+ for (size_t i = static_cast<size_t>(last_gc) + 1;
+ i < static_cast<size_t>(collector::kGcTypeMax); ++i) {
bool run_gc = false;
- GcType gc_type = static_cast<GcType>(i);
+ collector::GcType gc_type = static_cast<collector::GcType>(i);
switch (gc_type) {
- case kGcTypeSticky: {
+ case collector::kGcTypeSticky: {
const size_t alloc_space_size = alloc_space_->Size();
run_gc = alloc_space_size > min_alloc_space_size_for_sticky_gc_ &&
alloc_space_->Capacity() - alloc_space_size >= min_remaining_space_for_sticky_gc_;
break;
}
- case kGcTypePartial:
+ case collector::kGcTypePartial:
run_gc = have_zygote_space_;
break;
- case kGcTypeFull:
+ case collector::kGcTypeFull:
run_gc = true;
break;
default:
@@ -771,7 +822,7 @@ mirror::Object* Heap::Allocate(Thread* self, AllocSpace* space, size_t alloc_siz
if (run_gc) {
// If we actually ran a different type of Gc than requested, we can skip the index forwards.
- GcType gc_type_ran = CollectGarbageInternal(gc_type, kGcCauseForAlloc, false);
+ collector::GcType gc_type_ran = CollectGarbageInternal(gc_type, kGcCauseForAlloc, false);
DCHECK_GE(static_cast<size_t>(gc_type_ran), i);
i = static_cast<size_t>(gc_type_ran);
@@ -799,7 +850,7 @@ mirror::Object* Heap::Allocate(Thread* self, AllocSpace* space, size_t alloc_siz
<< " allocation";
// We don't need a WaitForConcurrentGcToComplete here either.
- CollectGarbageInternal(kGcTypeFull, kGcCauseForAlloc, true);
+ CollectGarbageInternal(collector::kGcTypeFull, kGcCauseForAlloc, true);
return TryToAllocate(self, space, alloc_size, true);
}
@@ -809,45 +860,54 @@ void Heap::SetTargetHeapUtilization(float target) {
target_utilization_ = target;
}
-int64_t Heap::GetMaxMemory() const {
- return growth_limit_;
-}
-
-int64_t Heap::GetTotalMemory() const {
- return GetMaxMemory();
-}
-
-int64_t Heap::GetFreeMemory() const {
- return GetMaxMemory() - num_bytes_allocated_;
-}
-
-size_t Heap::GetTotalBytesFreed() const {
- return total_bytes_freed_;
-}
-
-size_t Heap::GetTotalObjectsFreed() const {
- return total_objects_freed_;
+size_t Heap::GetObjectsAllocated() const {
+ size_t total = 0;
+ typedef std::vector<space::ContinuousSpace*>::const_iterator It;
+ for (It it = continuous_spaces_.begin(), end = continuous_spaces_.end(); it != end; ++it) {
+ space::ContinuousSpace* space = *it;
+ if (space->IsDlMallocSpace()) {
+ total += space->AsDlMallocSpace()->GetObjectsAllocated();
+ }
+ }
+ typedef std::vector<space::DiscontinuousSpace*>::const_iterator It2;
+ for (It2 it = discontinuous_spaces_.begin(), end = discontinuous_spaces_.end(); it != end; ++it) {
+ space::DiscontinuousSpace* space = *it;
+ total += space->AsLargeObjectSpace()->GetObjectsAllocated();
+ }
+ return total;
}
-size_t Heap::GetTotalObjectsAllocated() const {
- size_t total = large_object_space_->GetTotalObjectsAllocated();
- for (Spaces::const_iterator it = spaces_.begin(); it != spaces_.end(); ++it) {
- Space* space = *it;
- if (space->IsAllocSpace()) {
- total += space->AsAllocSpace()->GetTotalObjectsAllocated();
+size_t Heap::GetObjectsAllocatedEver() const {
+ size_t total = 0;
+ typedef std::vector<space::ContinuousSpace*>::const_iterator It;
+ for (It it = continuous_spaces_.begin(), end = continuous_spaces_.end(); it != end; ++it) {
+ space::ContinuousSpace* space = *it;
+ if (space->IsDlMallocSpace()) {
+ total += space->AsDlMallocSpace()->GetTotalObjectsAllocated();
}
}
+ typedef std::vector<space::DiscontinuousSpace*>::const_iterator It2;
+ for (It2 it = discontinuous_spaces_.begin(), end = discontinuous_spaces_.end(); it != end; ++it) {
+ space::DiscontinuousSpace* space = *it;
+ total += space->AsLargeObjectSpace()->GetTotalObjectsAllocated();
+ }
return total;
}
-size_t Heap::GetTotalBytesAllocated() const {
- size_t total = large_object_space_->GetTotalBytesAllocated();
- for (Spaces::const_iterator it = spaces_.begin(); it != spaces_.end(); ++it) {
- Space* space = *it;
- if (space->IsAllocSpace()) {
- total += space->AsAllocSpace()->GetTotalBytesAllocated();
+size_t Heap::GetBytesAllocatedEver() const {
+ size_t total = 0;
+ typedef std::vector<space::ContinuousSpace*>::const_iterator It;
+ for (It it = continuous_spaces_.begin(), end = continuous_spaces_.end(); it != end; ++it) {
+ space::ContinuousSpace* space = *it;
+ if (space->IsDlMallocSpace()) {
+ total += space->AsDlMallocSpace()->GetTotalBytesAllocated();
}
}
+ typedef std::vector<space::DiscontinuousSpace*>::const_iterator It2;
+ for (It2 it = discontinuous_spaces_.begin(), end = discontinuous_spaces_.end(); it != end; ++it) {
+ space::DiscontinuousSpace* space = *it;
+ total += space->AsLargeObjectSpace()->GetTotalBytesAllocated();
+ }
return total;
}
@@ -945,7 +1005,7 @@ class ReferringObjectsFinder {
// TODO: Fix lock analysis to not use NO_THREAD_SAFETY_ANALYSIS, requires support for
// annotalysis on visitors.
void operator()(const mirror::Object* o) const NO_THREAD_SAFETY_ANALYSIS {
- MarkSweep::VisitObjectReferences(o, *this);
+ collector::MarkSweep::VisitObjectReferences(o, *this);
}
// For MarkSweep::VisitObjectReferences.
@@ -983,7 +1043,7 @@ void Heap::CollectGarbage(bool clear_soft_references) {
// last GC will not have necessarily been cleared.
Thread* self = Thread::Current();
WaitForConcurrentGcToComplete(self);
- CollectGarbageInternal(kGcTypeFull, kGcCauseExplicit, clear_soft_references);
+ CollectGarbageInternal(collector::kGcTypeFull, kGcCauseExplicit, clear_soft_references);
}
void Heap::PreZygoteFork() {
@@ -1006,29 +1066,22 @@ void Heap::PreZygoteFork() {
FlushAllocStack();
}
- // Replace the first alloc space we find with a zygote space.
- // TODO: C++0x auto
- for (Spaces::iterator it = spaces_.begin(); it != spaces_.end(); ++it) {
- if ((*it)->IsAllocSpace()) {
- DlMallocSpace* zygote_space = (*it)->AsAllocSpace();
-
- // Turns the current alloc space into a Zygote space and obtain the new alloc space composed
- // of the remaining available heap memory.
- alloc_space_ = zygote_space->CreateZygoteSpace();
- alloc_space_->SetFootprintLimit(alloc_space_->Capacity());
-
- // Change the GC retention policy of the zygote space to only collect when full.
- zygote_space->SetGcRetentionPolicy(kGcRetentionPolicyFullCollect);
- AddSpace(alloc_space_);
- have_zygote_space_ = true;
- break;
- }
- }
+ // Turns the current alloc space into a Zygote space and obtain the new alloc space composed
+ // of the remaining available heap memory.
+ space::DlMallocSpace* zygote_space = alloc_space_;
+ alloc_space_ = zygote_space->CreateZygoteSpace();
+ alloc_space_->SetFootprintLimit(alloc_space_->Capacity());
+
+ // Change the GC retention policy of the zygote space to only collect when full.
+ zygote_space->SetGcRetentionPolicy(space::kGcRetentionPolicyFullCollect);
+ AddContinuousSpace(alloc_space_);
+ have_zygote_space_ = true;
// Reset the cumulative loggers since we now have a few additional timing phases.
// TODO: C++0x
- for (Collectors::const_iterator it = mark_sweep_collectors_.begin();
- it != mark_sweep_collectors_.end(); ++it) {
+ typedef std::vector<collector::MarkSweep*>::const_iterator It;
+ for (It it = mark_sweep_collectors_.begin(), end = mark_sweep_collectors_.end();
+ it != end; ++it) {
(*it)->ResetCumulativeStatistics();
}
}
@@ -1039,11 +1092,8 @@ void Heap::FlushAllocStack() {
allocation_stack_->Reset();
}
-size_t Heap::GetUsedMemorySize() const {
- return num_bytes_allocated_;
-}
-
-void Heap::MarkAllocStack(SpaceBitmap* bitmap, SpaceSetMap* large_objects, ObjectStack* stack) {
+void Heap::MarkAllocStack(accounting::SpaceBitmap* bitmap, accounting::SpaceSetMap* large_objects,
+ accounting::ObjectStack* stack) {
mirror::Object** limit = stack->End();
for (mirror::Object** it = stack->Begin(); it != limit; ++it) {
const mirror::Object* obj = *it;
@@ -1056,7 +1106,8 @@ void Heap::MarkAllocStack(SpaceBitmap* bitmap, SpaceSetMap* large_objects, Objec
}
}
-void Heap::UnMarkAllocStack(SpaceBitmap* bitmap, SpaceSetMap* large_objects, ObjectStack* stack) {
+void Heap::UnMarkAllocStack(accounting::SpaceBitmap* bitmap, accounting::SpaceSetMap* large_objects,
+ accounting::ObjectStack* stack) {
mirror::Object** limit = stack->End();
for (mirror::Object** it = stack->Begin(); it != limit; ++it) {
const mirror::Object* obj = *it;
@@ -1069,8 +1120,22 @@ void Heap::UnMarkAllocStack(SpaceBitmap* bitmap, SpaceSetMap* large_objects, Obj
}
}
-GcType Heap::CollectGarbageInternal(GcType gc_type, GcCause gc_cause, bool clear_soft_references) {
+collector::GcType Heap::CollectGarbageInternal(collector::GcType gc_type, GcCause gc_cause,
+ bool clear_soft_references) {
Thread* self = Thread::Current();
+
+ switch (gc_cause) {
+ case kGcCauseForAlloc:
+ ATRACE_BEGIN("GC (alloc)");
+ break;
+ case kGcCauseBackground:
+ ATRACE_BEGIN("GC (background)");
+ break;
+ case kGcCauseExplicit:
+ ATRACE_BEGIN("GC (explicit)");
+ break;
+ }
+
ScopedThreadStateChange tsc(self, kWaitingPerformingGc);
Locks::mutator_lock_->AssertNotHeld(self);
@@ -1103,31 +1168,37 @@ GcType Heap::CollectGarbageInternal(GcType gc_type, GcCause gc_cause, bool clear
// We need to do partial GCs every now and then to avoid the heap growing too much and
// fragmenting.
- if (gc_type == kGcTypeSticky && ++sticky_gc_count_ > partial_gc_frequency_) {
- gc_type = have_zygote_space_ ? kGcTypePartial : kGcTypeFull;
- }
- if (gc_type != kGcTypeSticky) {
+ // TODO: if sticky GCs are failing to free memory then we should lower the
+ // sticky_to_partial_gc_ratio_, if they are successful we can increase it.
+ if (gc_type == collector::kGcTypeSticky) {
+ ++sticky_gc_count_;
+ if (sticky_gc_count_ >= sticky_to_partial_gc_ratio_) {
+ gc_type = have_zygote_space_ ? collector::kGcTypePartial : collector::kGcTypeFull;
+ sticky_gc_count_ = 0;
+ }
+ } else {
sticky_gc_count_ = 0;
}
- uint64_t gc_start_time = NanoTime();
+ uint64_t gc_start_time_ns = NanoTime();
uint64_t gc_start_size = GetBytesAllocated();
// Approximate allocation rate in bytes / second.
- if (UNLIKELY(gc_start_time == last_gc_time_)) {
+ if (UNLIKELY(gc_start_time_ns == last_gc_time_ns_)) {
LOG(WARNING) << "Timers are broken (gc_start_time == last_gc_time_).";
}
- uint64_t ms_delta = NsToMs(gc_start_time - last_gc_time_);
+ uint64_t ms_delta = NsToMs(gc_start_time_ns - last_gc_time_ns_);
if (ms_delta != 0) {
- allocation_rate_ = (gc_start_size - last_gc_size_) * 1000 / ms_delta;
+ allocation_rate_ = ((gc_start_size - last_gc_size_) * 1000) / ms_delta;
VLOG(heap) << "Allocation rate: " << PrettySize(allocation_rate_) << "/s";
}
- DCHECK_LT(gc_type, kGcTypeMax);
- DCHECK_NE(gc_type, kGcTypeNone);
- MarkSweep* collector = NULL;
- for (Collectors::iterator it = mark_sweep_collectors_.begin();
- it != mark_sweep_collectors_.end(); ++it) {
- MarkSweep* cur_collector = *it;
+ DCHECK_LT(gc_type, collector::kGcTypeMax);
+ DCHECK_NE(gc_type, collector::kGcTypeNone);
+ collector::MarkSweep* collector = NULL;
+ typedef std::vector<collector::MarkSweep*>::iterator It;
+ for (It it = mark_sweep_collectors_.begin(), end = mark_sweep_collectors_.end();
+ it != end; ++it) {
+ collector::MarkSweep* cur_collector = *it;
if (cur_collector->IsConcurrent() == concurrent_gc_ && cur_collector->GetGcType() == gc_type) {
collector = cur_collector;
break;
@@ -1138,10 +1209,10 @@ GcType Heap::CollectGarbageInternal(GcType gc_type, GcCause gc_cause, bool clear
<< " and type=" << gc_type;
collector->clear_soft_references_ = clear_soft_references;
collector->Run();
- total_objects_freed_ += collector->GetFreedObjects();
- total_bytes_freed_ += collector->GetFreedBytes();
+ total_objects_freed_ever_ += collector->GetFreedObjects();
+ total_bytes_freed_ever_ += collector->GetFreedBytes();
- const size_t duration = collector->GetDuration();
+ const size_t duration = collector->GetDurationNs();
std::vector<uint64_t> pauses = collector->GetPauseTimes();
bool was_slow = duration > kSlowGcThreshold ||
(gc_cause == kGcCauseForAlloc && duration > kLongGcPauseThreshold);
@@ -1153,7 +1224,7 @@ GcType Heap::CollectGarbageInternal(GcType gc_type, GcCause gc_cause, bool clear
if (was_slow) {
const size_t percent_free = GetPercentFree();
- const size_t current_heap_size = GetUsedMemorySize();
+ const size_t current_heap_size = GetBytesAllocated();
const size_t total_memory = GetTotalMemory();
std::ostringstream pause_string;
for (size_t i = 0; i < pauses.size(); ++i) {
@@ -1166,7 +1237,7 @@ GcType Heap::CollectGarbageInternal(GcType gc_type, GcCause gc_cause, bool clear
<< PrettySize(total_memory) << ", " << "paused " << pause_string.str()
<< " total " << PrettyDuration((duration / 1000) * 1000);
if (VLOG_IS_ON(heap)) {
- LOG(INFO) << Dumpable<TimingLogger>(collector->GetTimings());
+ LOG(INFO) << Dumpable<base::NewTimingLogger>(collector->GetTimings());
}
}
@@ -1178,36 +1249,38 @@ GcType Heap::CollectGarbageInternal(GcType gc_type, GcCause gc_cause, bool clear
gc_complete_cond_->Broadcast(self);
}
// Inform DDMS that a GC completed.
+ ATRACE_END();
Dbg::GcDidFinish();
return gc_type;
}
-void Heap::UpdateAndMarkModUnion(MarkSweep* mark_sweep, TimingLogger& timings, GcType gc_type) {
- if (gc_type == kGcTypeSticky) {
+void Heap::UpdateAndMarkModUnion(collector::MarkSweep* mark_sweep, base::NewTimingLogger& timings,
+ collector::GcType gc_type) {
+ if (gc_type == collector::kGcTypeSticky) {
// Don't need to do anything for mod union table in this case since we are only scanning dirty
// cards.
return;
}
// Update zygote mod union table.
- if (gc_type == kGcTypePartial) {
+ if (gc_type == collector::kGcTypePartial) {
+ timings.NewSplit("UpdateZygoteModUnionTable");
zygote_mod_union_table_->Update();
- timings.AddSplit("UpdateZygoteModUnionTable");
+ timings.NewSplit("ZygoteMarkReferences");
zygote_mod_union_table_->MarkReferences(mark_sweep);
- timings.AddSplit("ZygoteMarkReferences");
}
// Processes the cards we cleared earlier and adds their objects into the mod-union table.
- mod_union_table_->Update();
- timings.AddSplit("UpdateModUnionTable");
+ timings.NewSplit("UpdateModUnionTable");
+ image_mod_union_table_->Update();
// Scans all objects in the mod-union table.
- mod_union_table_->MarkReferences(mark_sweep);
- timings.AddSplit("MarkImageToAllocSpaceReferences");
+ timings.NewSplit("MarkImageToAllocSpaceReferences");
+ image_mod_union_table_->MarkReferences(mark_sweep);
}
-void Heap::RootMatchesObjectVisitor(const mirror::Object* root, void* arg) {
+static void RootMatchesObjectVisitor(const mirror::Object* root, void* arg) {
mirror::Object* obj = reinterpret_cast<mirror::Object*>(arg);
if (root == obj) {
LOG(INFO) << "Object " << obj << " is a root";
@@ -1221,94 +1294,109 @@ class ScanVisitor {
}
};
+// Verify a reference from an object.
class VerifyReferenceVisitor {
public:
- VerifyReferenceVisitor(Heap* heap, bool* failed)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_,
- Locks::heap_bitmap_lock_)
- : heap_(heap),
- failed_(failed) {
+ VerifyReferenceVisitor(Heap* heap)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_, Locks::heap_bitmap_lock_)
+ : heap_(heap), failed_(false) {
+ }
+
+ bool Failed() const {
+ return failed_;
}
// TODO: Fix lock analysis to not use NO_THREAD_SAFETY_ANALYSIS, requires support for smarter
- // analysis.
+ // analysis on visitors.
void operator ()(const mirror::Object* obj, const mirror::Object* ref,
- const MemberOffset& /* offset */, bool /* is_static */) const
+ const MemberOffset& offset, bool /* is_static */) const
NO_THREAD_SAFETY_ANALYSIS {
// Verify that the reference is live.
- if (ref != NULL && !IsLive(ref)) {
- CardTable* card_table = heap_->GetCardTable();
- ObjectStack* alloc_stack = heap_->allocation_stack_.get();
- ObjectStack* live_stack = heap_->live_stack_.get();
-
- byte* card_addr = card_table->CardFromAddr(obj);
- LOG(ERROR) << "Object " << obj << " references dead object " << ref << "\n"
- << "IsDirty = " << (*card_addr == CardTable::kCardDirty) << "\n"
- << "Obj type " << PrettyTypeOf(obj) << "\n"
- << "Ref type " << PrettyTypeOf(ref);
- card_table->CheckAddrIsInCardTable(reinterpret_cast<const byte*>(obj));
- void* cover_begin = card_table->AddrFromCard(card_addr);
- void* cover_end = reinterpret_cast<void*>(reinterpret_cast<size_t>(cover_begin) +
- CardTable::kCardSize);
- LOG(ERROR) << "Card " << reinterpret_cast<void*>(card_addr) << " covers " << cover_begin
- << "-" << cover_end;
- SpaceBitmap* bitmap = heap_->GetLiveBitmap()->GetSpaceBitmap(obj);
-
- // Print out how the object is live.
- if (bitmap->Test(obj)) {
- LOG(ERROR) << "Object " << obj << " found in live bitmap";
- }
- if (std::binary_search(alloc_stack->Begin(), alloc_stack->End(), obj)) {
- LOG(ERROR) << "Object " << obj << " found in allocation stack";
+ if (UNLIKELY(ref != NULL && !IsLive(ref))) {
+ accounting::CardTable* card_table = heap_->GetCardTable();
+ accounting::ObjectStack* alloc_stack = heap_->allocation_stack_.get();
+ accounting::ObjectStack* live_stack = heap_->live_stack_.get();
+
+ if (obj != NULL) {
+ byte* card_addr = card_table->CardFromAddr(obj);
+ LOG(ERROR) << "Object " << obj << " references dead object " << ref << " at offset " << offset
+ << "\nIsDirty = " << (*card_addr == accounting::CardTable::kCardDirty)
+ << "\nObj type " << PrettyTypeOf(obj)
+ << "\nRef type " << PrettyTypeOf(ref);
+ card_table->CheckAddrIsInCardTable(reinterpret_cast<const byte*>(obj));
+ void* cover_begin = card_table->AddrFromCard(card_addr);
+ void* cover_end = reinterpret_cast<void*>(reinterpret_cast<size_t>(cover_begin) +
+ accounting::CardTable::kCardSize);
+ LOG(ERROR) << "Card " << reinterpret_cast<void*>(card_addr) << " covers " << cover_begin
+ << "-" << cover_end;
+ accounting::SpaceBitmap* bitmap = heap_->GetLiveBitmap()->GetContinuousSpaceBitmap(obj);
+
+ // Print out how the object is live.
+ if (bitmap != NULL && bitmap->Test(obj)) {
+ LOG(ERROR) << "Object " << obj << " found in live bitmap";
+ }
+ if (alloc_stack->Contains(const_cast<mirror::Object*>(obj))) {
+ LOG(ERROR) << "Object " << obj << " found in allocation stack";
+ }
+ if (live_stack->Contains(const_cast<mirror::Object*>(obj))) {
+ LOG(ERROR) << "Object " << obj << " found in live stack";
+ }
+ // Attempt to see if the card table missed the reference.
+ ScanVisitor scan_visitor;
+ byte* byte_cover_begin = reinterpret_cast<byte*>(card_table->AddrFromCard(card_addr));
+ card_table->Scan(bitmap, byte_cover_begin,
+ byte_cover_begin + accounting::CardTable::kCardSize,
+ scan_visitor, VoidFunctor());
+
+ // Search to see if any of the roots reference our object.
+ void* arg = const_cast<void*>(reinterpret_cast<const void*>(obj));
+ Runtime::Current()->VisitRoots(&RootMatchesObjectVisitor, arg, false, false);
+
+ // Search to see if any of the roots reference our reference.
+ arg = const_cast<void*>(reinterpret_cast<const void*>(ref));
+ Runtime::Current()->VisitRoots(&RootMatchesObjectVisitor, arg, false, false);
+ } else {
+ LOG(ERROR) << "Root references dead object " << ref << "\nRef type " << PrettyTypeOf(ref);
}
- if (std::binary_search(live_stack->Begin(), live_stack->End(), obj)) {
- LOG(ERROR) << "Object " << obj << " found in live stack";
+ if (alloc_stack->Contains(const_cast<mirror::Object*>(ref))) {
+ LOG(ERROR) << "Reference " << ref << " found in allocation stack!";
}
- if (std::binary_search(live_stack->Begin(), live_stack->End(), ref)) {
+ if (live_stack->Contains(const_cast<mirror::Object*>(ref))) {
LOG(ERROR) << "Reference " << ref << " found in live stack!";
}
-
- // Attempt to see if the card table missed the reference.
- ScanVisitor scan_visitor;
- byte* byte_cover_begin = reinterpret_cast<byte*>(card_table->AddrFromCard(card_addr));
- card_table->Scan(bitmap, byte_cover_begin, byte_cover_begin + CardTable::kCardSize,
- scan_visitor, VoidFunctor());
-
- // Search to see if any of the roots reference our object.
- void* arg = const_cast<void*>(reinterpret_cast<const void*>(obj));
- Runtime::Current()->VisitRoots(&Heap::RootMatchesObjectVisitor, arg);
- *failed_ = true;
+ heap_->image_mod_union_table_->Dump(LOG(ERROR) << "Image mod-union table: ");
+ heap_->zygote_mod_union_table_->Dump(LOG(ERROR) << "Zygote mod-union table: ");
+ failed_ = true;
}
}
bool IsLive(const mirror::Object* obj) const NO_THREAD_SAFETY_ANALYSIS {
- if (heap_->GetLiveBitmap()->Test(obj)) {
- return true;
- }
- ObjectStack* alloc_stack = heap_->allocation_stack_.get();
- // At this point we need to search the allocation since things in the live stack may get swept.
- // If the object is not either in the live bitmap or allocation stack, so the object must be
- // dead.
- return std::binary_search(alloc_stack->Begin(), alloc_stack->End(), obj);
+ return heap_->IsLiveObjectLocked(obj);
+ }
+
+ static void VerifyRoots(const mirror::Object* root, void* arg) {
+ VerifyReferenceVisitor* visitor = reinterpret_cast<VerifyReferenceVisitor*>(arg);
+ (*visitor)(NULL, root, MemberOffset(0), true);
}
private:
- Heap* heap_;
- bool* failed_;
+ Heap* const heap_;
+ mutable bool failed_;
};
+// Verify all references within an object, for use with HeapBitmap::Visit.
class VerifyObjectVisitor {
public:
- VerifyObjectVisitor(Heap* heap)
- : heap_(heap),
- failed_(false) {
-
+ VerifyObjectVisitor(Heap* heap) : heap_(heap), failed_(false) {
}
void operator ()(const mirror::Object* obj) const
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_, Locks::heap_bitmap_lock_) {
- VerifyReferenceVisitor visitor(heap_, const_cast<bool*>(&failed_));
- MarkSweep::VisitObjectReferences(obj, visitor);
+ // Note: we are verifying the references in obj but not obj itself, this is because obj must
+ // be live or else how did we find it in the live bitmap?
+ VerifyReferenceVisitor visitor(heap_);
+ collector::MarkSweep::VisitObjectReferences(obj, visitor);
+ failed_ = failed_ || visitor.Failed();
}
bool Failed() const {
@@ -1316,18 +1404,19 @@ class VerifyObjectVisitor {
}
private:
- Heap* heap_;
- bool failed_;
+ Heap* const heap_;
+ mutable bool failed_;
};
// Must do this with mutators suspended since we are directly accessing the allocation stacks.
bool Heap::VerifyHeapReferences() {
Locks::mutator_lock_->AssertExclusiveHeld(Thread::Current());
// Lets sort our allocation stacks so that we can efficiently binary search them.
- std::sort(allocation_stack_->Begin(), allocation_stack_->End());
- std::sort(live_stack_->Begin(), live_stack_->End());
+ allocation_stack_->Sort();
+ live_stack_->Sort();
// Perform the verification.
VerifyObjectVisitor visitor(this);
+ Runtime::Current()->VisitRoots(VerifyReferenceVisitor::VerifyRoots, &visitor, false, false);
GetLiveBitmap()->Visit(visitor);
// We don't want to verify the objects in the allocation stack since they themselves may be
// pointing to dead objects if they are not reachable.
@@ -1343,8 +1432,7 @@ class VerifyReferenceCardVisitor {
VerifyReferenceCardVisitor(Heap* heap, bool* failed)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_,
Locks::heap_bitmap_lock_)
- : heap_(heap),
- failed_(failed) {
+ : heap_(heap), failed_(failed) {
}
// TODO: Fix lock analysis to not use NO_THREAD_SAFETY_ANALYSIS, requires support for
@@ -1354,7 +1442,7 @@ class VerifyReferenceCardVisitor {
// Filter out class references since changing an object's class does not mark the card as dirty.
// Also handles large objects, since the only reference they hold is a class reference.
if (ref != NULL && !ref->IsClass()) {
- CardTable* card_table = heap_->GetCardTable();
+ accounting::CardTable* card_table = heap_->GetCardTable();
// If the object is not dirty and it is referencing something in the live stack other than
// class, then it must be on a dirty card.
if (!card_table->AddrIsInCardTable(obj)) {
@@ -1363,9 +1451,9 @@ class VerifyReferenceCardVisitor {
} else if (!card_table->IsDirty(obj)) {
// Card should be either kCardDirty if it got re-dirtied after we aged it, or
// kCardDirty - 1 if it didnt get touched since we aged it.
- ObjectStack* live_stack = heap_->live_stack_.get();
- if (std::binary_search(live_stack->Begin(), live_stack->End(), ref)) {
- if (std::binary_search(live_stack->Begin(), live_stack->End(), obj)) {
+ accounting::ObjectStack* live_stack = heap_->live_stack_.get();
+ if (live_stack->Contains(const_cast<mirror::Object*>(ref))) {
+ if (live_stack->Contains(const_cast<mirror::Object*>(obj))) {
LOG(ERROR) << "Object " << obj << " found in live stack";
}
if (heap_->GetLiveBitmap()->Test(obj)) {
@@ -1406,8 +1494,8 @@ class VerifyReferenceCardVisitor {
}
private:
- Heap* heap_;
- bool* failed_;
+ Heap* const heap_;
+ bool* const failed_;
};
class VerifyLiveStackReferences {
@@ -1421,7 +1509,7 @@ class VerifyLiveStackReferences {
void operator ()(const mirror::Object* obj) const
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_, Locks::heap_bitmap_lock_) {
VerifyReferenceCardVisitor visitor(heap_, const_cast<bool*>(&failed_));
- MarkSweep::VisitObjectReferences(obj, visitor);
+ collector::MarkSweep::VisitObjectReferences(obj, visitor);
}
bool Failed() const {
@@ -1429,7 +1517,7 @@ class VerifyLiveStackReferences {
}
private:
- Heap* heap_;
+ Heap* const heap_;
bool failed_;
};
@@ -1437,7 +1525,7 @@ bool Heap::VerifyMissingCardMarks() {
Locks::mutator_lock_->AssertExclusiveHeld(Thread::Current());
// We need to sort the live stack since we binary search it.
- std::sort(live_stack_->Begin(), live_stack_->End());
+ live_stack_->Sort();
VerifyLiveStackReferences visitor(this);
GetLiveBitmap()->Visit(visitor);
@@ -1458,30 +1546,31 @@ void Heap::SwapStacks() {
// Sort the live stack so that we can quickly binary search it later.
if (verify_object_mode_ > kNoHeapVerification) {
- std::sort(live_stack_->Begin(), live_stack_->End());
+ live_stack_->Sort();
}
}
-void Heap::ProcessCards(TimingLogger& timings) {
- // Clear image space cards and keep track of cards we cleared in the mod-union table.
- for (Spaces::iterator it = spaces_.begin(); it != spaces_.end(); ++it) {
- ContinuousSpace* space = *it;
+void Heap::ProcessCards(base::NewTimingLogger& timings) {
+ // Clear cards and keep track of cards cleared in the mod-union table.
+ typedef std::vector<space::ContinuousSpace*>::iterator It;
+ for (It it = continuous_spaces_.begin(), end = continuous_spaces_.end(); it != end; ++it) {
+ space::ContinuousSpace* space = *it;
if (space->IsImageSpace()) {
- mod_union_table_->ClearCards(*it);
- timings.AddSplit("ModUnionClearCards");
- } else if (space->GetGcRetentionPolicy() == kGcRetentionPolicyFullCollect) {
+ timings.NewSplit("ModUnionClearCards");
+ image_mod_union_table_->ClearCards(space);
+ } else if (space->IsZygoteSpace()) {
+ timings.NewSplit("ZygoteModUnionClearCards");
zygote_mod_union_table_->ClearCards(space);
- timings.AddSplit("ZygoteModUnionClearCards");
} else {
// No mod union table for the AllocSpace. Age the cards so that the GC knows that these cards
// were dirty before the GC started.
+ timings.NewSplit("AllocSpaceClearCards");
card_table_->ModifyCardsAtomic(space->Begin(), space->End(), AgeCardVisitor(), VoidFunctor());
- timings.AddSplit("AllocSpaceClearCards");
}
}
}
-void Heap::PreGcVerification(GarbageCollector* gc) {
+void Heap::PreGcVerification(collector::GarbageCollector* gc) {
ThreadList* thread_list = Runtime::Current()->GetThreadList();
Thread* self = Thread::Current();
@@ -1516,44 +1605,50 @@ void Heap::PreGcVerification(GarbageCollector* gc) {
ReaderMutexLock reader_lock(self, *Locks::heap_bitmap_lock_);
zygote_mod_union_table_->Update();
zygote_mod_union_table_->Verify();
- mod_union_table_->Update();
- mod_union_table_->Verify();
+ image_mod_union_table_->Update();
+ image_mod_union_table_->Verify();
thread_list->ResumeAll();
}
}
-void Heap::PreSweepingGcVerification(GarbageCollector* gc) {
+void Heap::PreSweepingGcVerification(collector::GarbageCollector* gc) {
ThreadList* thread_list = Runtime::Current()->GetThreadList();
- Thread* self = Thread::Current();
// Called before sweeping occurs since we want to make sure we are not going so reclaim any
// reachable objects.
if (verify_post_gc_heap_) {
+ Thread* self = Thread::Current();
+ CHECK_NE(self->GetState(), kRunnable);
+ Locks::mutator_lock_->SharedUnlock(self);
thread_list->SuspendAll();
- WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
- // Swapping bound bitmaps does nothing.
- live_bitmap_.swap(mark_bitmap_);
- if (!VerifyHeapReferences()) {
- LOG(FATAL) << "Post " << gc->GetName() << "Gc verification failed";
+ {
+ WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
+ // Swapping bound bitmaps does nothing.
+ gc->SwapBitmaps();
+ if (!VerifyHeapReferences()) {
+ LOG(FATAL) << "Post " << gc->GetName() << "GC verification failed";
+ }
+ gc->SwapBitmaps();
}
- live_bitmap_.swap(mark_bitmap_);
thread_list->ResumeAll();
+ Locks::mutator_lock_->SharedLock(self);
}
}
-void Heap::PostGcVerification(GarbageCollector* gc) {
+void Heap::PostGcVerification(collector::GarbageCollector* gc) {
Thread* self = Thread::Current();
if (verify_system_weaks_) {
ReaderMutexLock mu(self, *Locks::heap_bitmap_lock_);
- MarkSweep* mark_sweep = down_cast<MarkSweep*>(gc);
+ collector::MarkSweep* mark_sweep = down_cast<collector::MarkSweep*>(gc);
mark_sweep->VerifySystemWeaks();
}
}
-GcType Heap::WaitForConcurrentGcToComplete(Thread* self) {
- GcType last_gc_type = kGcTypeNone;
+collector::GcType Heap::WaitForConcurrentGcToComplete(Thread* self) {
+ collector::GcType last_gc_type = collector::kGcTypeNone;
if (concurrent_gc_) {
+ ATRACE_BEGIN("GC: Wait For Concurrent");
bool do_wait;
uint64_t wait_start = NanoTime();
{
@@ -1578,12 +1673,13 @@ GcType Heap::WaitForConcurrentGcToComplete(Thread* self) {
LOG(INFO) << "WaitForConcurrentGcToComplete blocked for " << PrettyDuration(wait_time);
}
}
+ ATRACE_END();
}
return last_gc_type;
}
void Heap::DumpForSigQuit(std::ostream& os) {
- os << "Heap: " << GetPercentFree() << "% free, " << PrettySize(GetUsedMemorySize()) << "/"
+ os << "Heap: " << GetPercentFree() << "% free, " << PrettySize(GetBytesAllocated()) << "/"
<< PrettySize(GetTotalMemory()) << "; " << GetObjectsAllocated() << " objects\n";
DumpGcPerformanceInfo(os);
}
@@ -1606,7 +1702,7 @@ void Heap::GrowForUtilization(uint64_t gc_duration) {
// This doesn't actually resize any memory. It just lets the heap grow more when necessary.
const size_t bytes_allocated = GetBytesAllocated();
last_gc_size_ = bytes_allocated;
- last_gc_time_ = NanoTime();
+ last_gc_time_ns_ = NanoTime();
size_t target_size = bytes_allocated / GetTargetHeapUtilization();
if (target_size > bytes_allocated + max_free_) {
@@ -1617,20 +1713,23 @@ void Heap::GrowForUtilization(uint64_t gc_duration) {
SetIdealFootprint(target_size);
- // Calculate when to perform the next ConcurrentGC if we have enough free memory.
- if (concurrent_gc_ && GetFreeMemory() >= concurrent_min_free_) {
+ // Calculate when to perform the next ConcurrentGC.
+ if (concurrent_gc_) {
// Calculate the estimated GC duration.
double gc_duration_seconds = NsToMs(gc_duration) / 1000.0;
// Estimate how many remaining bytes we will have when we need to start the next GC.
size_t remaining_bytes = allocation_rate_ * gc_duration_seconds;
- if (remaining_bytes < max_allowed_footprint_) {
+ remaining_bytes = std::max(remaining_bytes, kMinConcurrentRemainingBytes);
+ if (UNLIKELY(remaining_bytes > max_allowed_footprint_)) {
+ // A never going to happen situation that from the estimated allocation rate we will exceed
+ // the applications entire footprint with the given estimated allocation rate. Schedule
+ // another GC straight away.
+ concurrent_start_bytes_ = bytes_allocated;
+ } else {
// Start a concurrent GC when we get close to the estimated remaining bytes. When the
// allocation rate is very high, remaining_bytes could tell us that we should start a GC
// right away.
concurrent_start_bytes_ = std::max(max_allowed_footprint_ - remaining_bytes, bytes_allocated);
- } else {
- // The estimated rate is so high that we should request another GC straight away.
- concurrent_start_bytes_ = bytes_allocated;
}
DCHECK_LE(concurrent_start_bytes_, max_allowed_footprint_);
DCHECK_LE(max_allowed_footprint_, growth_limit_);
@@ -1736,30 +1835,6 @@ void Heap::AddFinalizerReference(Thread* self, mirror::Object* object) {
arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'V');
}
-size_t Heap::GetBytesAllocated() const {
- return num_bytes_allocated_;
-}
-
-size_t Heap::GetObjectsAllocated() const {
- size_t total = 0;
- // TODO: C++0x
- for (Spaces::const_iterator it = spaces_.begin(); it != spaces_.end(); ++it) {
- Space* space = *it;
- if (space->IsAllocSpace()) {
- total += space->AsAllocSpace()->GetNumObjectsAllocated();
- }
- }
- return total;
-}
-
-size_t Heap::GetConcurrentStartSize() const {
- return concurrent_start_size_;
-}
-
-size_t Heap::GetConcurrentMinFree() const {
- return concurrent_min_free_;
-}
-
void Heap::EnqueueClearedReferences(mirror::Object** cleared) {
DCHECK(cleared != NULL);
if (*cleared != NULL) {
@@ -1811,11 +1886,11 @@ void Heap::ConcurrentGC(Thread* self) {
}
// Wait for any GCs currently running to finish.
- if (WaitForConcurrentGcToComplete(self) == kGcTypeNone) {
+ if (WaitForConcurrentGcToComplete(self) == collector::kGcTypeNone) {
if (alloc_space_->Size() > min_alloc_space_size_for_sticky_gc_) {
- CollectGarbageInternal(kGcTypeSticky, kGcCauseBackground, false);
+ CollectGarbageInternal(collector::kGcTypeSticky, kGcCauseBackground, false);
} else {
- CollectGarbageInternal(kGcTypePartial, kGcCauseBackground, false);
+ CollectGarbageInternal(collector::kGcTypePartial, kGcCauseBackground, false);
}
}
}
@@ -1835,8 +1910,8 @@ void Heap::RequestHeapTrim() {
// not how much use we're making of those pages.
uint64_t ms_time = MilliTime();
float utilization =
- static_cast<float>(alloc_space_->GetNumBytesAllocated()) / alloc_space_->Size();
- if ((utilization > 0.75f) || ((ms_time - last_trim_time_) < 2 * 1000)) {
+ static_cast<float>(alloc_space_->GetBytesAllocated()) / alloc_space_->Size();
+ if ((utilization > 0.75f) || ((ms_time - last_trim_time_ms_) < 2 * 1000)) {
// Don't bother trimming the alloc space if it's more than 75% utilized, or if a
// heap trim occurred in the last two seconds.
return;
@@ -1861,7 +1936,7 @@ void Heap::RequestHeapTrim() {
return;
}
- last_trim_time_ = ms_time;
+ last_trim_time_ms_ = ms_time;
JNIEnv* env = self->GetJniEnv();
DCHECK(WellKnownClasses::java_lang_Daemons != NULL);
DCHECK(WellKnownClasses::java_lang_Daemons_requestHeapTrim != NULL);
@@ -1875,4 +1950,5 @@ size_t Heap::Trim() {
return alloc_space_->Trim();
}
+} // namespace gc
} // namespace art
diff --git a/src/heap.h b/src/gc/heap.h
index 642c43689d..d86c7dc7d2 100644
--- a/src/heap.h
+++ b/src/gc/heap.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ART_SRC_HEAP_H_
-#define ART_SRC_HEAP_H_
+#ifndef ART_SRC_GC_HEAP_H_
+#define ART_SRC_GC_HEAP_H_
#include <iosfwd>
#include <string>
@@ -23,10 +23,9 @@
#include "atomic_integer.h"
#include "base/timing_logger.h"
-#include "gc/atomic_stack.h"
-#include "gc/card_table.h"
-#include "gc/gc_type.h"
-#include "gc/heap_bitmap.h"
+#include "gc/accounting/atomic_stack.h"
+#include "gc/accounting/card_table.h"
+#include "gc/collector/gc_type.h"
#include "globals.h"
#include "gtest/gtest.h"
#include "locks.h"
@@ -35,32 +34,44 @@
#include "thread_pool.h"
namespace art {
-namespace mirror {
-class Class;
-class Object;
-} // namespace mirror
-class AllocSpace;
+
class ConditionVariable;
-class DlMallocSpace;
-class GarbageCollector;
-class HeapBitmap;
-class ImageSpace;
-class LargeObjectSpace;
-class MarkSweep;
-class ModUnionTable;
class Mutex;
-class Space;
-class SpaceTest;
class StackVisitor;
class Thread;
class TimingLogger;
-typedef std::vector<ContinuousSpace*> Spaces;
+namespace mirror {
+ class Class;
+ class Object;
+} // namespace mirror
+
+namespace gc {
+namespace accounting {
+ class HeapBitmap;
+ class ModUnionTable;
+ class SpaceSetMap;
+} // namespace accounting
+
+namespace collector {
+ class GarbageCollector;
+ class MarkSweep;
+} // namespace collector
+
+namespace space {
+ class AllocSpace;
+ class DiscontinuousSpace;
+ class DlMallocSpace;
+ class ImageSpace;
+ class LargeObjectSpace;
+ class Space;
+ class SpaceTest;
+} // namespace space
class AgeCardVisitor {
public:
byte operator ()(byte card) const {
- if (card == CardTable::kCardDirty) {
+ if (card == accounting::CardTable::kCardDirty) {
return card - 1;
} else {
return 0;
@@ -68,9 +79,14 @@ class AgeCardVisitor {
}
};
+// What caused the GC?
enum GcCause {
+ // GC triggered by a failed allocation. Thread doing allocation is blocked waiting for GC before
+ // retrying allocation.
kGcCauseForAlloc,
+ // A background GC trying to ensure there is free memory ahead of allocations.
kGcCauseBackground,
+ // An explicit System.gc() call.
kGcCauseExplicit,
};
std::ostream& operator<<(std::ostream& os, const GcCause& policy);
@@ -120,10 +136,8 @@ class Heap {
// Check sanity of all live references.
void VerifyHeap() LOCKS_EXCLUDED(Locks::heap_bitmap_lock_);
- static void RootMatchesObjectVisitor(const mirror::Object* root, void* arg);
bool VerifyHeapReferences()
- EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_, Locks::mutator_lock_);
bool VerifyMissingCardMarks()
EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -139,20 +153,12 @@ class Heap {
SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
// Initiates an explicit garbage collection.
- void CollectGarbage(bool clear_soft_references)
- LOCKS_EXCLUDED(Locks::mutator_lock_);
+ void CollectGarbage(bool clear_soft_references) LOCKS_EXCLUDED(Locks::mutator_lock_);
// Does a concurrent GC, should only be called by the GC daemon thread
// through runtime.
void ConcurrentGC(Thread* self) LOCKS_EXCLUDED(Locks::runtime_shutdown_lock_);
- // Implements java.lang.Runtime.maxMemory.
- int64_t GetMaxMemory() const;
- // Implements java.lang.Runtime.totalMemory.
- int64_t GetTotalMemory() const;
- // Implements java.lang.Runtime.freeMemory.
- int64_t GetFreeMemory() const;
-
// Implements VMDebug.countInstancesOfClass and JDWP VM_InstanceCount.
// The boolean decides whether to use IsAssignableFrom or == when comparing classes.
void CountInstances(const std::vector<mirror::Class*>& classes, bool use_is_assignable_from,
@@ -188,14 +194,14 @@ class Heap {
// Blocks the caller until the garbage collector becomes idle and returns
// true if we waited for the GC to complete.
- GcType WaitForConcurrentGcToComplete(Thread* self) LOCKS_EXCLUDED(gc_complete_lock_);
+ collector::GcType WaitForConcurrentGcToComplete(Thread* self) LOCKS_EXCLUDED(gc_complete_lock_);
- const Spaces& GetSpaces() const {
- return spaces_;
+ const std::vector<space::ContinuousSpace*>& GetContinuousSpaces() const {
+ return continuous_spaces_;
}
- Spaces& GetSpaces() {
- return spaces_;
+ const std::vector<space::DiscontinuousSpace*>& GetDiscontinuousSpaces() const {
+ return discontinuous_spaces_;
}
void SetReferenceOffsets(MemberOffset reference_referent_offset,
@@ -257,47 +263,78 @@ class Heap {
card_table_->MarkCard(dst);
}
- CardTable* GetCardTable() {
+ accounting::CardTable* GetCardTable() const {
return card_table_.get();
}
void AddFinalizerReference(Thread* self, mirror::Object* object);
- size_t GetBytesAllocated() const;
+ // Returns the number of bytes currently allocated.
+ size_t GetBytesAllocated() const {
+ return num_bytes_allocated_;
+ }
+
+ // Returns the number of objects currently allocated.
size_t GetObjectsAllocated() const;
- size_t GetConcurrentStartSize() const;
- size_t GetConcurrentMinFree() const;
- size_t GetUsedMemorySize() const;
// Returns the total number of objects allocated since the heap was created.
- size_t GetTotalObjectsAllocated() const;
+ size_t GetObjectsAllocatedEver() const;
// Returns the total number of bytes allocated since the heap was created.
- size_t GetTotalBytesAllocated() const;
+ size_t GetBytesAllocatedEver() const;
// Returns the total number of objects freed since the heap was created.
- size_t GetTotalObjectsFreed() const;
+ size_t GetObjectsFreedEver() const {
+ return total_objects_freed_ever_;
+ }
// Returns the total number of bytes freed since the heap was created.
- size_t GetTotalBytesFreed() const;
+ size_t GetBytesFreedEver() const {
+ return total_bytes_freed_ever_;
+ }
+
+ // Implements java.lang.Runtime.maxMemory, returning the maximum amount of memory a program can
+ // consume. For a regular VM this would relate to the -Xmx option and would return -1 if no Xmx
+ // were specified. Android apps start with a growth limit (small heap size) which is
+ // cleared/extended for large apps.
+ int64_t GetMaxMemory() const {
+ return growth_limit_;
+ }
+
+ // Implements java.lang.Runtime.totalMemory, returning the amount of memory consumed by an
+ // application.
+ int64_t GetTotalMemory() const {
+ // TODO: we use the footprint limit here which is conservative wrt number of pages really used.
+ // We could implement a more accurate count across all spaces.
+ return max_allowed_footprint_;
+ }
- // Functions for getting the bitmap which corresponds to an object's address.
- // This is probably slow, TODO: use better data structure like binary tree .
- ContinuousSpace* FindSpaceFromObject(const mirror::Object*) const;
+ // Implements java.lang.Runtime.freeMemory.
+ int64_t GetFreeMemory() const {
+ return GetTotalMemory() - num_bytes_allocated_;
+ }
+
+ // Get the space that corresponds to an object's address. Current implementation searches all
+ // spaces in turn. If fail_ok is false then failing to find a space will cause an abort.
+ // TODO: consider using faster data structure like binary tree.
+ space::ContinuousSpace* FindContinuousSpaceFromObject(const mirror::Object*, bool fail_ok) const;
+ space::DiscontinuousSpace* FindDiscontinuousSpaceFromObject(const mirror::Object*,
+ bool fail_ok) const;
+ space::Space* FindSpaceFromObject(const mirror::Object*, bool fail_ok) const;
void DumpForSigQuit(std::ostream& os);
size_t Trim();
- HeapBitmap* GetLiveBitmap() SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_) {
+ accounting::HeapBitmap* GetLiveBitmap() SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_) {
return live_bitmap_.get();
}
- HeapBitmap* GetMarkBitmap() SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_) {
+ accounting::HeapBitmap* GetMarkBitmap() SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_) {
return mark_bitmap_.get();
}
- ObjectStack* GetLiveStack() SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_) {
+ accounting::ObjectStack* GetLiveStack() SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_) {
return live_stack_.get();
}
@@ -308,24 +345,32 @@ class Heap {
EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
// Mark all the objects in the allocation stack in the specified bitmap.
- void MarkAllocStack(SpaceBitmap* bitmap, SpaceSetMap* large_objects, ObjectStack* stack)
+ void MarkAllocStack(accounting::SpaceBitmap* bitmap, accounting::SpaceSetMap* large_objects,
+ accounting::ObjectStack* stack)
EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
// Unmark all the objects in the allocation stack in the specified bitmap.
- void UnMarkAllocStack(SpaceBitmap* bitmap, SpaceSetMap* large_objects, ObjectStack* stack)
+ void UnMarkAllocStack(accounting::SpaceBitmap* bitmap, accounting::SpaceSetMap* large_objects,
+ accounting::ObjectStack* stack)
EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
// Update and mark mod union table based on gc type.
- void UpdateAndMarkModUnion(MarkSweep* mark_sweep, TimingLogger& timings, GcType gc_type)
+ void UpdateAndMarkModUnion(collector::MarkSweep* mark_sweep, base::NewTimingLogger& timings,
+ collector::GcType gc_type)
EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
// DEPRECATED: Should remove in "near" future when support for multiple image spaces is added.
// Assumes there is only one image space.
- ImageSpace* GetImageSpace();
- DlMallocSpace* GetAllocSpace();
- LargeObjectSpace* GetLargeObjectsSpace() {
- return large_object_space_.get();
+ space::ImageSpace* GetImageSpace() const;
+
+ space::DlMallocSpace* GetAllocSpace() const {
+ return alloc_space_;
}
+
+ space::LargeObjectSpace* GetLargeObjectsSpace() const {
+ return large_object_space_;
+ }
+
void DumpSpaces();
// UnReserve the address range where the oat file will be placed.
@@ -344,12 +389,12 @@ class Heap {
private:
// Allocates uninitialized storage. Passing in a null space tries to place the object in the
// large object space.
- mirror::Object* Allocate(Thread* self, AllocSpace* space, size_t num_bytes)
+ mirror::Object* Allocate(Thread* self, space::AllocSpace* space, size_t num_bytes)
LOCKS_EXCLUDED(Locks::thread_suspend_count_lock_)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Try to allocate a number of bytes, this function never does any GCs.
- mirror::Object* TryToAllocate(Thread* self, AllocSpace* space, size_t alloc_size, bool grow)
+ mirror::Object* TryToAllocate(Thread* self, space::AllocSpace* space, size_t alloc_size, bool grow)
LOCKS_EXCLUDED(Locks::thread_suspend_count_lock_)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -365,14 +410,16 @@ class Heap {
// Sometimes CollectGarbageInternal decides to run a different Gc than you requested. Returns
// which type of Gc was actually ran.
- GcType CollectGarbageInternal(GcType gc_plan, GcCause gc_cause, bool clear_soft_references)
+ collector::GcType CollectGarbageInternal(collector::GcType gc_plan, GcCause gc_cause,
+ bool clear_soft_references)
LOCKS_EXCLUDED(gc_complete_lock_,
Locks::heap_bitmap_lock_,
Locks::thread_suspend_count_lock_);
- void PreGcVerification(GarbageCollector* gc);
- void PreSweepingGcVerification(GarbageCollector* gc);
- void PostGcVerification(GarbageCollector* gc);
+ void PreGcVerification(collector::GarbageCollector* gc);
+ void PreSweepingGcVerification(collector::GarbageCollector* gc)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ void PostGcVerification(collector::GarbageCollector* gc);
// Given the current contents of the alloc space, increase the allowed heap footprint to match
// the target utilization ratio. This should only be called immediately after a full garbage
@@ -381,7 +428,9 @@ class Heap {
size_t GetPercentFree();
- void AddSpace(ContinuousSpace* space) LOCKS_EXCLUDED(Locks::heap_bitmap_lock_);
+ void AddContinuousSpace(space::ContinuousSpace* space) LOCKS_EXCLUDED(Locks::heap_bitmap_lock_);
+ void AddDiscontinuousSpace(space::DiscontinuousSpace* space)
+ LOCKS_EXCLUDED(Locks::heap_bitmap_lock_);
// No thread saftey analysis since we call this everywhere and it is impossible to find a proper
// lock ordering for it.
@@ -394,26 +443,32 @@ class Heap {
void SwapStacks();
// Clear cards and update the mod union table.
- void ProcessCards(TimingLogger& timings);
+ void ProcessCards(base::NewTimingLogger& timings);
- Spaces spaces_;
+ // All-known continuous spaces, where objects lie within fixed bounds.
+ std::vector<space::ContinuousSpace*> continuous_spaces_;
- // A map that we use to temporarily reserve address range for the oat file.
- UniquePtr<MemMap> oat_file_map_;
+ // All-known discontinuous spaces, where objects may be placed throughout virtual memory.
+ std::vector<space::DiscontinuousSpace*> discontinuous_spaces_;
+
+ // The allocation space we are currently allocating into.
+ space::DlMallocSpace* alloc_space_;
+
+ // The large object space we are currently allocating into.
+ space::LargeObjectSpace* large_object_space_;
- // The alloc space which we are currently allocating into.
- DlMallocSpace* alloc_space_;
+ // The card table, dirtied by the write barrier.
+ UniquePtr<accounting::CardTable> card_table_;
// The mod-union table remembers all of the references from the image space to the alloc /
- // zygote spaces.
- UniquePtr<ModUnionTable> mod_union_table_;
+ // zygote spaces to allow the card table to be cleared.
+ UniquePtr<accounting::ModUnionTable> image_mod_union_table_;
// This table holds all of the references from the zygote space to the alloc space.
- UniquePtr<ModUnionTable> zygote_mod_union_table_;
+ UniquePtr<accounting::ModUnionTable> zygote_mod_union_table_;
- UniquePtr<CardTable> card_table_;
-
- // True for concurrent mark sweep GC, false for mark sweep.
+ // What kind of concurrency behavior is the runtime after? True for concurrent mark sweep GC,
+ // false for stop-the-world mark sweep.
const bool concurrent_gc_;
// If we have a zygote space.
@@ -424,40 +479,43 @@ class Heap {
Mutex* gc_complete_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
UniquePtr<ConditionVariable> gc_complete_cond_ GUARDED_BY(gc_complete_lock_);
- // Reference queue lock
- UniquePtr<Mutex> reference_queue_lock_;
+ // Mutex held when adding references to reference queues.
+ // TODO: move to a UniquePtr, currently annotalysis is confused that UniquePtr isn't lockable.
+ Mutex* reference_queue_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
// True while the garbage collector is running.
volatile bool is_gc_running_ GUARDED_BY(gc_complete_lock_);
// Last Gc type we ran. Used by WaitForConcurrentGc to know which Gc was waited on.
- volatile GcType last_gc_type_ GUARDED_BY(gc_complete_lock_);
-
- // If enabled, causes Gc for alloc when heap size reaches the current footprint limit before the
- // Gc updates it.
- const bool enforce_heap_growth_rate_;
+ volatile collector::GcType last_gc_type_ GUARDED_BY(gc_complete_lock_);
// Maximum size that the heap can reach.
- size_t capacity_;
+ const size_t capacity_;
+ // The size the heap is limited to. This is initially smaller than capacity, but for largeHeap
+ // programs it is "cleared" making it the same as capacity.
size_t growth_limit_;
+ // When the number of bytes allocated exceeds the footprint TryAllocate returns NULL indicating
+ // a GC should be triggered.
size_t max_allowed_footprint_;
- // Minimum bytes before concurrent GC starts.
- size_t concurrent_start_size_;
- size_t concurrent_min_free_;
+ // When num_bytes_allocated_ exceeds this amount then a concurrent GC should be requested so that
+ // it completes ahead of an allocation failing.
size_t concurrent_start_bytes_;
- // Number of bytes allocated since the last Gc, we use this to help determine when to schedule concurrent GCs.
+ // Number of back-to-back sticky mark sweep collections.
size_t sticky_gc_count_;
- size_t total_bytes_freed_;
- size_t total_objects_freed_;
+ // After how many sticky GCs we force to do a partial GC instead of sticky mark bits GC.
+ const size_t sticky_to_partial_gc_ratio_;
- // Primitive objects larger than this size are put in the large object space.
- size_t large_object_threshold_;
+ // Since the heap was created, how many bytes have been freed.
+ size_t total_bytes_freed_ever_;
- // Large object space.
- UniquePtr<LargeObjectSpace> large_object_space_;
+ // Since the heap was created, how many objects have been freed.
+ size_t total_objects_freed_ever_;
+
+ // Primitive objects larger than this size are put in the large object space.
+ const size_t large_object_threshold_;
// Number of bytes allocated. Adjusted after each allocation and free.
AtomicInteger num_bytes_allocated_;
@@ -472,9 +530,6 @@ class Heap {
// Parallel GC data structures.
UniquePtr<ThreadPool> thread_pool_;
- // After how many GCs we force to do a partial GC instead of sticky mark bits GC.
- const size_t partial_gc_frequency_;
-
// Sticky mark bits GC has some overhead, so if we have less a few megabytes of AllocSpace then
// it's probably better to just do a partial GC.
const size_t min_alloc_space_size_for_sticky_gc_;
@@ -483,31 +538,34 @@ class Heap {
// normal GC, it is important to not use it when we are almost out of memory.
const size_t min_remaining_space_for_sticky_gc_;
- // Last trim time
- uint64_t last_trim_time_;
+ // The last time a heap trim occurred.
+ uint64_t last_trim_time_ms_;
- // The time at which the last GC ended.
- uint64_t last_gc_time_;
+ // The nanosecond time at which the last GC ended.
+ uint64_t last_gc_time_ns_;
// How many bytes were allocated at the end of the last GC.
uint64_t last_gc_size_;
- // Estimated allocation rate (bytes / second).
+ // Estimated allocation rate (bytes / second). Computed between the time of the last GC cycle
+ // and the start of the current one.
uint64_t allocation_rate_;
- UniquePtr<HeapBitmap> live_bitmap_ GUARDED_BY(Locks::heap_bitmap_lock_);
- UniquePtr<HeapBitmap> mark_bitmap_ GUARDED_BY(Locks::heap_bitmap_lock_);
+ // For a GC cycle, a bitmap that is set corresponding to the
+ UniquePtr<accounting::HeapBitmap> live_bitmap_ GUARDED_BY(Locks::heap_bitmap_lock_);
+ UniquePtr<accounting::HeapBitmap> mark_bitmap_ GUARDED_BY(Locks::heap_bitmap_lock_);
// Mark stack that we reuse to avoid re-allocating the mark stack.
- UniquePtr<ObjectStack> mark_stack_;
+ UniquePtr<accounting::ObjectStack> mark_stack_;
// Allocation stack, new allocations go here so that we can do sticky mark bits. This enables us
// to use the live bitmap as the old mark bitmap.
const size_t max_allocation_stack_size_;
- UniquePtr<ObjectStack> allocation_stack_;
+ bool is_allocation_stack_sorted_;
+ UniquePtr<accounting::ObjectStack> allocation_stack_;
// Second allocation stack so that we can process allocation with the heap unlocked.
- UniquePtr<ObjectStack> live_stack_;
+ UniquePtr<accounting::ObjectStack> live_stack_;
// offset of java.lang.ref.Reference.referent
MemberOffset reference_referent_offset_;
@@ -544,22 +602,22 @@ class Heap {
// The current state of heap verification, may be enabled or disabled.
HeapVerificationMode verify_object_mode_;
- typedef std::vector<MarkSweep*> Collectors;
- Collectors mark_sweep_collectors_;
+ std::vector<collector::MarkSweep*> mark_sweep_collectors_;
+
+ // A map that we use to temporarily reserve address range for the oat file.
+ UniquePtr<MemMap> oat_file_map_;
- friend class MarkSweep;
+ friend class collector::MarkSweep;
friend class VerifyReferenceCardVisitor;
friend class VerifyReferenceVisitor;
friend class VerifyObjectVisitor;
friend class ScopedHeapLock;
- FRIEND_TEST(SpaceTest, AllocAndFree);
- FRIEND_TEST(SpaceTest, AllocAndFreeList);
- FRIEND_TEST(SpaceTest, ZygoteSpace);
- friend class SpaceTest;
+ friend class space::SpaceTest;
DISALLOW_IMPLICIT_CONSTRUCTORS(Heap);
};
+} // namespace gc
} // namespace art
-#endif // ART_SRC_HEAP_H_
+#endif // ART_SRC_GC_HEAP_H_
diff --git a/src/gc/heap_bitmap.cc b/src/gc/heap_bitmap.cc
deleted file mode 100644
index cef6884374..0000000000
--- a/src/gc/heap_bitmap.cc
+++ /dev/null
@@ -1,49 +0,0 @@
-#include "heap_bitmap.h"
-#include "space.h"
-
-namespace art {
-
-void HeapBitmap::ReplaceBitmap(SpaceBitmap* old_bitmap, SpaceBitmap* new_bitmap) {
- // TODO: C++0x auto
- for (Bitmaps::iterator it = bitmaps_.begin(); it != bitmaps_.end(); ++it) {
- if (*it == old_bitmap) {
- *it = new_bitmap;
- return;
- }
- }
- LOG(FATAL) << "bitmap " << static_cast<const void*>(old_bitmap) << " not found";
-}
-
-void HeapBitmap::AddSpaceBitmap(SpaceBitmap* bitmap) {
- DCHECK(bitmap != NULL);
-
- // Check for interval overlap.
- for (Bitmaps::const_iterator it = bitmaps_.begin(); it != bitmaps_.end(); ++it) {
- SpaceBitmap* cur_bitmap = *it;
- if (bitmap->HeapBegin() < cur_bitmap->HeapLimit() &&
- bitmap->HeapLimit() > cur_bitmap->HeapBegin()) {
- LOG(FATAL) << "Overlapping space bitmaps added to heap bitmap!";
- }
- }
- bitmaps_.push_back(bitmap);
-}
-
-void HeapBitmap::SetLargeObjects(SpaceSetMap* large_objects) {
- DCHECK(large_objects != NULL);
- large_objects_ = large_objects;
-}
-
-HeapBitmap::HeapBitmap(Heap* heap) : heap_(heap), large_objects_(NULL) {
-
-}
-
-void HeapBitmap::Walk(SpaceBitmap::Callback* callback, void* arg) {
- // TODO: C++0x auto
- for (Bitmaps::iterator it = bitmaps_.begin(); it != bitmaps_.end(); ++it) {
- (*it)->Walk(callback, arg);
- }
-
- large_objects_->Walk(callback, arg);
-}
-
-} // namespace art
diff --git a/src/gc/heap_bitmap.h b/src/gc/heap_bitmap.h
deleted file mode 100644
index 87e08483f5..0000000000
--- a/src/gc/heap_bitmap.h
+++ /dev/null
@@ -1,104 +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.
- */
-
-#ifndef ART_SRC_GC_HEAP_BITMAP_H_
-#define ART_SRC_GC_HEAP_BITMAP_H_
-
-#include "locks.h"
-#include "space_bitmap.h"
-
-namespace art {
-class Heap;
-
-class HeapBitmap {
- public:
- bool Test(const mirror::Object* obj) SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_) {
- SpaceBitmap* bitmap = GetSpaceBitmap(obj);
- if (LIKELY(bitmap != NULL)) {
- return bitmap->Test(obj);
- } else {
- return large_objects_->Test(obj);
- }
- }
-
- void Clear(const mirror::Object* obj)
- EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_) {
- SpaceBitmap* bitmap = GetSpaceBitmap(obj);
- if (LIKELY(bitmap != NULL)) {
- bitmap->Clear(obj);
- } else {
- large_objects_->Clear(obj);
- }
- }
-
- void Set(const mirror::Object* obj)
- EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_) {
- SpaceBitmap* bitmap = GetSpaceBitmap(obj);
- if (LIKELY(bitmap != NULL)) {
- bitmap->Set(obj);
- } else {
- large_objects_->Set(obj);
- }
- }
-
- SpaceBitmap* GetSpaceBitmap(const mirror::Object* obj) {
- // TODO: C++0x auto
- for (Bitmaps::iterator it = bitmaps_.begin(); it != bitmaps_.end(); ++it) {
- if ((*it)->HasAddress(obj)) {
- return *it;
- }
- }
- return NULL;
- }
-
- void Walk(SpaceBitmap::Callback* callback, void* arg)
- SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
-
- template <typename Visitor>
- void Visit(const Visitor& visitor)
- EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
- // Find and replace a bitmap pointer, this is used by for the bitmap swapping in the GC.
- void ReplaceBitmap(SpaceBitmap* old_bitmap, SpaceBitmap* new_bitmap)
- EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
-
- HeapBitmap(Heap* heap);
-
- inline SpaceSetMap* GetLargeObjects() const {
- return large_objects_;
- }
-
- void SetLargeObjects(SpaceSetMap* large_objects);
-
- private:
-
- const Heap* const heap_;
-
- void AddSpaceBitmap(SpaceBitmap* bitmap);
-
- typedef std::vector<SpaceBitmap*> Bitmaps;
- Bitmaps bitmaps_;
-
- // Large object sets.
- SpaceSetMap* large_objects_;
-
- friend class Heap;
-};
-
-} // namespace art
-
-#endif // ART_SRC_GC_HEAP_BITMAP_H_
diff --git a/src/heap_test.cc b/src/gc/heap_test.cc
index 8bed7e3175..02708e8341 100644
--- a/src/heap_test.cc
+++ b/src/gc/heap_test.cc
@@ -15,14 +15,15 @@
*/
#include "common_test.h"
-#include "gc/card_table-inl.h"
-#include "gc/space_bitmap-inl.h"
+#include "gc/accounting/card_table-inl.h"
+#include "gc/accounting/space_bitmap-inl.h"
#include "mirror/class-inl.h"
#include "mirror/object-inl.h"
#include "mirror/object_array-inl.h"
#include "sirt_ref.h"
namespace art {
+namespace gc {
class HeapTest : public CommonTest {};
@@ -56,9 +57,15 @@ TEST_F(HeapTest, GarbageCollectClassLinkerInit) {
TEST_F(HeapTest, HeapBitmapCapacityTest) {
byte* heap_begin = reinterpret_cast<byte*>(0x1000);
- const size_t heap_capacity = SpaceBitmap::kAlignment * (sizeof(intptr_t) * 8 + 1);
- UniquePtr<SpaceBitmap> bitmap(SpaceBitmap::Create("test bitmap", heap_begin, heap_capacity));
- bitmap->Set(reinterpret_cast<const mirror::Object*>(&heap_begin[heap_capacity - SpaceBitmap::kAlignment]));
+ const size_t heap_capacity = accounting::SpaceBitmap::kAlignment * (sizeof(intptr_t) * 8 + 1);
+ UniquePtr<accounting::SpaceBitmap> bitmap(accounting::SpaceBitmap::Create("test bitmap",
+ heap_begin,
+ heap_capacity));
+ mirror::Object* fake_end_of_heap_object =
+ reinterpret_cast<mirror::Object*>(&heap_begin[heap_capacity -
+ accounting::SpaceBitmap::kAlignment]);
+ bitmap->Set(fake_end_of_heap_object);
}
+} // namespace gc
} // namespace art
diff --git a/src/gc/mod_union_table-inl.h b/src/gc/mod_union_table-inl.h
deleted file mode 100644
index c1c69fb379..0000000000
--- a/src/gc/mod_union_table-inl.h
+++ /dev/null
@@ -1,64 +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.
- */
-
-#ifndef ART_SRC_GC_MOD_UNION_TABLE_INL_H_
-#define ART_SRC_GC_MOD_UNION_TABLE_INL_H_
-
-#include "mod_union_table.h"
-
-namespace art {
-
-template <typename Implementation>
-class ModUnionTableToZygoteAllocspace : public Implementation {
-public:
- ModUnionTableToZygoteAllocspace(Heap* heap) : Implementation(heap) {
- }
-
- bool AddReference(const mirror::Object* /* obj */, const mirror::Object* ref) {
- const Spaces& spaces = Implementation::GetHeap()->GetSpaces();
- for (Spaces::const_iterator it = spaces.begin(); it != spaces.end(); ++it) {
- if ((*it)->Contains(ref)) {
- return (*it)->IsAllocSpace();
- }
- }
- // Assume it points to a large object.
- // TODO: Check.
- return true;
- }
-};
-
-template <typename Implementation>
-class ModUnionTableToAllocspace : public Implementation {
-public:
- ModUnionTableToAllocspace(Heap* heap) : Implementation(heap) {
- }
-
- bool AddReference(const mirror::Object* /* obj */, const mirror::Object* ref) {
- const Spaces& spaces = Implementation::GetHeap()->GetSpaces();
- for (Spaces::const_iterator it = spaces.begin(); it != spaces.end(); ++it) {
- if ((*it)->Contains(ref)) {
- return (*it)->GetGcRetentionPolicy() == kGcRetentionPolicyAlwaysCollect;
- }
- }
- // Assume it points to a large object.
- // TODO: Check.
- return true;
- }
-};
-
-} // namespace art
-
-#endif // ART_SRC_GC_MOD_UNION_TABLE_INL_H_
diff --git a/src/gc/space.h b/src/gc/space.h
deleted file mode 100644
index d2bcd53725..0000000000
--- a/src/gc/space.h
+++ /dev/null
@@ -1,463 +0,0 @@
-/*
- * Copyright (C) 2011 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_GC_SPACE_H_
-#define ART_SRC_GC_SPACE_H_
-
-#include <string>
-
-#include "UniquePtr.h"
-#include "base/macros.h"
-#include "base/mutex.h"
-#include "globals.h"
-#include "image.h"
-#include "dlmalloc.h"
-#include "mem_map.h"
-
-namespace art {
-
-static const bool kDebugSpaces = kIsDebugBuild;
-
-namespace mirror {
-class Object;
-} // namespace mirror
-class DlMallocSpace;
-class ImageSpace;
-class LargeObjectSpace;
-class SpaceBitmap;
-
-enum GcRetentionPolicy {
- kGcRetentionPolicyNeverCollect,
- kGcRetentionPolicyAlwaysCollect,
- kGcRetentionPolicyFullCollect, // Collect only for full GC
-};
-std::ostream& operator<<(std::ostream& os, const GcRetentionPolicy& policy);
-
-enum SpaceType {
- kSpaceTypeImageSpace,
- kSpaceTypeAllocSpace,
- kSpaceTypeZygoteSpace,
- kSpaceTypeLargeObjectSpace,
-};
-std::ostream& operator<<(std::ostream& os, const SpaceType& space_type);
-
-// A space contains memory allocated for managed objects.
-class Space {
- public:
- virtual bool CanAllocateInto() const = 0;
- virtual bool IsCompactible() const = 0;
- virtual bool Contains(const mirror::Object* obj) const = 0;
- virtual SpaceType GetType() const = 0;
- virtual GcRetentionPolicy GetGcRetentionPolicy() const = 0;
- virtual std::string GetName() const = 0;
-
- ImageSpace* AsImageSpace();
- DlMallocSpace* AsAllocSpace();
- DlMallocSpace* AsZygoteSpace();
- LargeObjectSpace* AsLargeObjectSpace();
-
- bool IsImageSpace() const {
- return GetType() == kSpaceTypeImageSpace;
- }
-
- bool IsAllocSpace() const {
- return GetType() == kSpaceTypeAllocSpace || GetType() == kSpaceTypeZygoteSpace;
- }
-
- bool IsZygoteSpace() const {
- return GetType() == kSpaceTypeZygoteSpace;
- }
-
- bool IsLargeObjectSpace() const {
- return GetType() == kSpaceTypeLargeObjectSpace;
- }
-
- virtual void Dump(std::ostream& /* os */) const { }
-
- virtual ~Space() {}
-
- protected:
- Space() { }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(Space);
-};
-
-// AllocSpace interface.
-class AllocSpace {
- public:
- virtual bool CanAllocateInto() const {
- return true;
- }
-
- // General statistics
- virtual uint64_t GetNumBytesAllocated() const = 0;
- virtual uint64_t GetNumObjectsAllocated() const = 0;
- virtual uint64_t GetTotalBytesAllocated() const = 0;
- virtual uint64_t GetTotalObjectsAllocated() const = 0;
-
- // Allocate num_bytes without allowing growth.
- virtual mirror::Object* Alloc(Thread* self, size_t num_bytes) = 0;
-
- // Return the storage space required by obj.
- virtual size_t AllocationSize(const mirror::Object* obj) = 0;
-
- // Returns how many bytes were freed.
- virtual size_t Free(Thread* self, mirror::Object* ptr) = 0;
-
- // Returns how many bytes were freed.
- virtual size_t FreeList(Thread* self, size_t num_ptrs, mirror::Object** ptrs) = 0;
-
- protected:
- AllocSpace() {}
- virtual ~AllocSpace() {}
-
- private:
- DISALLOW_COPY_AND_ASSIGN(AllocSpace);
-};
-
-// Continuous spaces have bitmaps, and an address range.
-class ContinuousSpace : public Space {
- public:
- // Address at which the space begins
- byte* Begin() const {
- return begin_;
- }
-
- // Address at which the space ends, which may vary as the space is filled.
- byte* End() const {
- return end_;
- }
-
- // Current size of space
- size_t Size() const {
- return End() - Begin();
- }
-
- virtual SpaceBitmap* GetLiveBitmap() const = 0;
- virtual SpaceBitmap* GetMarkBitmap() const = 0;
-
- // Is object within this space?
- bool HasAddress(const mirror::Object* obj) const {
- const byte* byte_ptr = reinterpret_cast<const byte*>(obj);
- return Begin() <= byte_ptr && byte_ptr < End();
- }
-
- virtual bool Contains(const mirror::Object* obj) const {
- return HasAddress(obj);
- }
-
- virtual ~ContinuousSpace() {}
-
- virtual std::string GetName() const {
- return name_;
- }
-
- virtual GcRetentionPolicy GetGcRetentionPolicy() const {
- return gc_retention_policy_;
- }
-
- protected:
- ContinuousSpace(const std::string& name, byte* begin, byte* end,
- GcRetentionPolicy gc_retention_policy);
-
- std::string name_;
- GcRetentionPolicy gc_retention_policy_;
-
- // The beginning of the storage for fast access.
- byte* begin_;
-
- // Current end of the space.
- byte* end_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ContinuousSpace);
-};
-
-class DiscontinuousSpace : public virtual Space {
- public:
- // Is object within this space?
- virtual bool Contains(const mirror::Object* obj) const = 0;
-
- virtual std::string GetName() const {
- return name_;
- }
-
- virtual GcRetentionPolicy GetGcRetentionPolicy() const {
- return gc_retention_policy_;
- }
-
-protected:
- DiscontinuousSpace(const std::string& name, GcRetentionPolicy gc_retention_policy);
-
-private:
- std::string name_;
- GcRetentionPolicy gc_retention_policy_;
-
- DISALLOW_COPY_AND_ASSIGN(DiscontinuousSpace);
-};
-
-std::ostream& operator<<(std::ostream& os, const Space& space);
-
-class MemMapSpace : public ContinuousSpace {
- public:
- // Maximum which the mapped space can grow to.
- virtual size_t Capacity() const {
- return mem_map_->Size();
- }
-
- // Size of the space without a limit on its growth. By default this is just the Capacity, but
- // for the allocation space we support starting with a small heap and then extending it.
- virtual size_t NonGrowthLimitCapacity() const {
- return Capacity();
- }
-
- protected:
- MemMapSpace(const std::string& name, MemMap* mem_map, size_t initial_size,
- GcRetentionPolicy gc_retention_policy);
-
- MemMap* GetMemMap() {
- return mem_map_.get();
- }
-
- const MemMap* GetMemMap() const {
- return mem_map_.get();
- }
-
- private:
- // Underlying storage of the space
- UniquePtr<MemMap> mem_map_;
-
- DISALLOW_COPY_AND_ASSIGN(MemMapSpace);
-};
-
-// An alloc space is a space where objects may be allocated and garbage collected.
-class DlMallocSpace : public MemMapSpace, public AllocSpace {
- public:
- typedef void(*WalkCallback)(void *start, void *end, size_t num_bytes, void* callback_arg);
-
- virtual bool CanAllocateInto() const {
- return true;
- }
-
- virtual bool IsCompactible() const {
- return false;
- }
-
- virtual SpaceType GetType() const {
- return kSpaceTypeAllocSpace;
- }
-
- // Create a AllocSpace with the requested sizes. The requested
- // base address is not guaranteed to be granted, if it is required,
- // the caller should call Begin on the returned space to confirm
- // the request was granted.
- static DlMallocSpace* Create(const std::string& name, size_t initial_size, size_t growth_limit,
- size_t capacity, byte* requested_begin);
-
- // Allocate num_bytes without allowing the underlying mspace to grow.
- virtual mirror::Object* AllocWithGrowth(Thread* self, size_t num_bytes);
-
- // Allocate num_bytes allowing the underlying mspace to grow.
- virtual mirror::Object* Alloc(Thread* self, size_t num_bytes);
-
- // Return the storage space required by obj.
- virtual size_t AllocationSize(const mirror::Object* obj);
- virtual size_t Free(Thread* self, mirror::Object* ptr);
- virtual size_t FreeList(Thread* self, size_t num_ptrs, mirror::Object** ptrs);
-
- void* MoreCore(intptr_t increment);
-
- void* GetMspace() const {
- return mspace_;
- }
-
- // Hands unused pages back to the system.
- size_t Trim();
-
- // Perform a mspace_inspect_all which calls back for each allocation chunk. The chunk may not be
- // in use, indicated by num_bytes equaling zero.
- void Walk(WalkCallback callback, void* arg);
-
- // Returns the number of bytes that the heap is allowed to obtain from the system via MoreCore.
- size_t GetFootprintLimit();
-
- // Set the maximum number of bytes that the heap is allowed to obtain from the system via
- // MoreCore. Note this is used to stop the mspace growing beyond the limit to Capacity. When
- // allocations fail we GC before increasing the footprint limit and allowing the mspace to grow.
- void SetFootprintLimit(size_t limit);
-
- // Removes the fork time growth limit on capacity, allowing the application to allocate up to the
- // maximum reserved size of the heap.
- void ClearGrowthLimit() {
- growth_limit_ = NonGrowthLimitCapacity();
- }
-
- // Override capacity so that we only return the possibly limited capacity
- virtual size_t Capacity() const {
- return growth_limit_;
- }
-
- // The total amount of memory reserved for the alloc space
- virtual size_t NonGrowthLimitCapacity() const {
- return GetMemMap()->Size();
- }
-
- virtual SpaceBitmap* GetLiveBitmap() const {
- return live_bitmap_.get();
- }
-
- virtual SpaceBitmap* GetMarkBitmap() const {
- return mark_bitmap_.get();
- }
-
- virtual void Dump(std::ostream& os) const;
-
- void SetGrowthLimit(size_t growth_limit);
-
- // Swap the live and mark bitmaps of this space. This is used by the GC for concurrent sweeping.
- virtual void SwapBitmaps();
-
- // Turn ourself into a zygote space and return a new alloc space which has our unused memory.
- DlMallocSpace* CreateZygoteSpace();
-
- void SetGcRetentionPolicy(GcRetentionPolicy gc_retention_policy) {
- gc_retention_policy_ = gc_retention_policy;
- }
-
- virtual uint64_t GetNumBytesAllocated() const {
- return num_bytes_allocated_;
- }
-
- virtual uint64_t GetNumObjectsAllocated() const {
- return num_objects_allocated_;
- }
-
- virtual uint64_t GetTotalBytesAllocated() const {
- return total_bytes_allocated_;
- }
-
- virtual uint64_t GetTotalObjectsAllocated() const {
- return total_objects_allocated_;
- }
-
- private:
- size_t InternalAllocationSize(const mirror::Object* obj);
- mirror::Object* AllocWithoutGrowthLocked(size_t num_bytes) EXCLUSIVE_LOCKS_REQUIRED(lock_);
-
- UniquePtr<SpaceBitmap> live_bitmap_;
- UniquePtr<SpaceBitmap> mark_bitmap_;
- UniquePtr<SpaceBitmap> temp_bitmap_;
-
- // Approximate number of bytes which have been allocated into the space.
- size_t num_bytes_allocated_;
- size_t num_objects_allocated_;
- size_t total_bytes_allocated_;
- size_t total_objects_allocated_;
-
- static size_t bitmap_index_;
-
- DlMallocSpace(const std::string& name, MemMap* mem_map, void* mspace, byte* begin, byte* end,
- size_t growth_limit);
-
- bool Init(size_t initial_size, size_t maximum_size, size_t growth_size, byte* requested_base);
-
- static void* CreateMallocSpace(void* base, size_t morecore_start, size_t initial_size);
-
- // The boundary tag overhead.
- static const size_t kChunkOverhead = kWordSize;
-
- // Used to ensure mutual exclusion when the allocation spaces data structures are being modified.
- Mutex lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
-
- // Underlying malloc space
- void* const mspace_;
-
- // The capacity of the alloc space until such time that ClearGrowthLimit is called.
- // The underlying mem_map_ controls the maximum size we allow the heap to grow to. The growth
- // limit is a value <= to the mem_map_ capacity used for ergonomic reasons because of the zygote.
- // Prior to forking the zygote the heap will have a maximally sized mem_map_ but the growth_limit_
- // will be set to a lower value. The growth_limit_ is used as the capacity of the alloc_space_,
- // however, capacity normally can't vary. In the case of the growth_limit_ it can be cleared
- // one time by a call to ClearGrowthLimit.
- size_t growth_limit_;
-
- friend class MarkSweep;
-
- DISALLOW_COPY_AND_ASSIGN(DlMallocSpace);
-};
-
-// An image space is a space backed with a memory mapped image
-class ImageSpace : public MemMapSpace {
- public:
- virtual bool CanAllocateInto() const {
- return false;
- }
-
- virtual bool IsCompactible() const {
- return false;
- }
-
- virtual SpaceType GetType() const {
- return kSpaceTypeImageSpace;
- }
-
- // create a Space from an image file. cannot be used for future allocation or collected.
- static ImageSpace* Create(const std::string& image)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
- const ImageHeader& GetImageHeader() const {
- return *reinterpret_cast<ImageHeader*>(Begin());
- }
-
- const std::string GetImageFilename() const {
- return GetName();
- }
-
- // Mark the objects defined in this space in the given live bitmap
- void RecordImageAllocations(SpaceBitmap* live_bitmap) const
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
- virtual SpaceBitmap* GetLiveBitmap() const {
- return live_bitmap_.get();
- }
-
- virtual SpaceBitmap* GetMarkBitmap() const {
- // ImageSpaces have the same bitmap for both live and marked. This helps reduce the number of
- // special cases to test against.
- return live_bitmap_.get();
- }
-
- virtual void Dump(std::ostream& os) const;
-
- private:
- friend class Space;
-
- UniquePtr<SpaceBitmap> live_bitmap_;
- static size_t bitmap_index_;
-
- ImageSpace(const std::string& name, MemMap* mem_map);
-
- DISALLOW_COPY_AND_ASSIGN(ImageSpace);
-};
-
-// Callback for dlmalloc_inspect_all or mspace_inspect_all that will madvise(2) unused
-// pages back to the kernel.
-void MspaceMadviseCallback(void* start, void* end, size_t used_bytes, void* /*arg*/);
-
-} // namespace art
-
-#endif // ART_SRC_GC_SPACE_H_
diff --git a/src/gc/space.cc b/src/gc/space/dlmalloc_space.cc
index 1d3ee28d5b..02acd286dd 100644
--- a/src/gc/space.cc
+++ b/src/gc/space/dlmalloc_space.cc
@@ -13,33 +13,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-#include "space.h"
-
-#include "base/logging.h"
-#include "base/stl_util.h"
-#include "base/unix_file/fd_file.h"
-#include "card_table.h"
-#include "dlmalloc.h"
-#include "image.h"
-#include "mirror/array.h"
-#include "mirror/abstract_method.h"
-#include "mirror/class-inl.h"
-#include "mirror/object-inl.h"
-#include "os.h"
+#include "dlmalloc_space.h"
+#include "gc/accounting/card_table.h"
+#include "gc/heap.h"
#include "runtime.h"
-#include "space_bitmap.h"
-#include "space_bitmap-inl.h"
#include "thread.h"
-#include "UniquePtr.h"
#include "utils.h"
-namespace art {
+//#include <valgrind/memcheck.h>
+#include <valgrind.h>
-static const bool kPrefetchDuringDlMallocFreeList = true;
-
-// Magic padding value that we use to check for buffer overruns.
-static const word kPaddingValue = 0xBAC0BAC0;
+namespace art {
+namespace gc {
+namespace space {
// TODO: Remove define macro
#define CHECK_MEMORY_CALL(call, args, what) \
@@ -51,45 +37,86 @@ static const word kPaddingValue = 0xBAC0BAC0;
} \
} while (false)
-ImageSpace* Space::AsImageSpace() {
- DCHECK_EQ(GetType(), kSpaceTypeImageSpace);
- return down_cast<ImageSpace*>(down_cast<MemMapSpace*>(this));
-}
-
-DlMallocSpace* Space::AsAllocSpace() {
- DCHECK_EQ(GetType(), kSpaceTypeAllocSpace);
- return down_cast<DlMallocSpace*>(down_cast<MemMapSpace*>(this));
-}
+static const bool kPrefetchDuringDlMallocFreeList = true;
-DlMallocSpace* Space::AsZygoteSpace() {
- DCHECK_EQ(GetType(), kSpaceTypeZygoteSpace);
- return down_cast<DlMallocSpace*>(down_cast<MemMapSpace*>(this));
-}
+// Number of bytes to use as a red zone (rdz). A red zone of this size will be placed before and
+// after each allocation. 8 bytes provides long/double alignment.
+const size_t kValgrindRedZoneBytes = 8;
+
+// A specialization of DlMallocSpace that provides information to valgrind wrt allocations.
+class ValgrindDlMallocSpace : public DlMallocSpace {
+ public:
+ virtual mirror::Object* AllocWithGrowth(Thread* self, size_t num_bytes) {
+ void* obj_with_rdz = DlMallocSpace::AllocWithGrowth(self, num_bytes + (2 * kValgrindRedZoneBytes));
+ if (obj_with_rdz != NULL) {
+ //VALGRIND_MAKE_MEM_UNDEFINED();
+ mirror::Object* result = reinterpret_cast<mirror::Object*>(reinterpret_cast<byte*>(obj_with_rdz) +
+ kValgrindRedZoneBytes);
+ VALGRIND_MEMPOOL_ALLOC(GetMspace(), result, num_bytes);
+ LOG(INFO) << "AllocWithGrowth on " << self << " = " << obj_with_rdz
+ << " of size " << num_bytes;
+ return result;
+ } else {
+ return NULL;
+ }
+ }
-LargeObjectSpace* Space::AsLargeObjectSpace() {
- DCHECK_EQ(GetType(), kSpaceTypeLargeObjectSpace);
- return reinterpret_cast<LargeObjectSpace*>(this);
-}
+ virtual mirror::Object* Alloc(Thread* self, size_t num_bytes) {
+ void* obj_with_rdz = DlMallocSpace::Alloc(self, num_bytes + (2 * kValgrindRedZoneBytes));
+ if (obj_with_rdz != NULL) {
+ mirror::Object* result = reinterpret_cast<mirror::Object*>(reinterpret_cast<byte*>(obj_with_rdz) +
+ kValgrindRedZoneBytes);
+ VALGRIND_MEMPOOL_ALLOC(GetMspace(), result, num_bytes);
+ LOG(INFO) << "Alloc on " << self << " = " << obj_with_rdz
+ << " of size " << num_bytes;
+ return result;
+ } else {
+ return NULL;
+ }
+ }
-ContinuousSpace::ContinuousSpace(const std::string& name, byte* begin, byte* end,
- GcRetentionPolicy gc_retention_policy)
- : name_(name), gc_retention_policy_(gc_retention_policy), begin_(begin), end_(end) {
+ virtual size_t AllocationSize(const mirror::Object* obj) {
+ const void* obj_after_rdz = reinterpret_cast<const void*>(obj);
+ size_t result = DlMallocSpace::AllocationSize(
+ reinterpret_cast<const mirror::Object*>(reinterpret_cast<const byte*>(obj_after_rdz) -
+ kValgrindRedZoneBytes));
+ return result - (2 * kValgrindRedZoneBytes);
+ }
-}
+ virtual size_t Free(Thread* self, mirror::Object* ptr) {
+ void* obj_after_rdz = reinterpret_cast<void*>(ptr);
+ void* obj_with_rdz = reinterpret_cast<byte*>(obj_after_rdz) - kValgrindRedZoneBytes;
+ LOG(INFO) << "Free on " << self << " of " << obj_with_rdz;
+ size_t freed = DlMallocSpace::Free(self, reinterpret_cast<mirror::Object*>(obj_with_rdz));
+ VALGRIND_MEMPOOL_FREE(GetMspace(), obj_after_rdz);
+ return freed - (2 * kValgrindRedZoneBytes);
+ }
-DiscontinuousSpace::DiscontinuousSpace(const std::string& name,
- GcRetentionPolicy gc_retention_policy)
- : name_(name), gc_retention_policy_(gc_retention_policy) {
+ virtual size_t FreeList(Thread* self, size_t num_ptrs, mirror::Object** ptrs) {
+ size_t freed = 0;
+ for (size_t i = 0; i < num_ptrs; i++) {
+ void* obj_after_rdz = reinterpret_cast<void*>(ptrs[i]);
+ void* obj_with_rdz = reinterpret_cast<byte*>(obj_after_rdz) - kValgrindRedZoneBytes;
+ LOG(INFO) << "FreeList on " << self << " of " << obj_with_rdz;
+ freed += DlMallocSpace::Free(self, reinterpret_cast<mirror::Object*>(obj_with_rdz));
+ VALGRIND_MEMPOOL_FREE(GetMspace(), obj_after_rdz);
+ }
+ return freed - (2 * kValgrindRedZoneBytes * num_ptrs);
+ }
-}
+ ValgrindDlMallocSpace(const std::string& name, MemMap* mem_map, void* mspace, byte* begin,
+ byte* end, size_t growth_limit) :
+ DlMallocSpace(name, mem_map, mspace, begin, end, growth_limit) {
+ VALGRIND_CREATE_MEMPOOL(GetMspace(), kValgrindRedZoneBytes, true);
+ }
-MemMapSpace::MemMapSpace(const std::string& name, MemMap* mem_map, size_t initial_size,
- GcRetentionPolicy gc_retention_policy)
- : ContinuousSpace(name, mem_map->Begin(), mem_map->Begin() + initial_size, gc_retention_policy),
- mem_map_(mem_map)
-{
+ virtual ~ValgrindDlMallocSpace() {
+ VALGRIND_DESTROY_MEMPOOL(GetMspace());
+ }
-}
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ValgrindDlMallocSpace);
+};
size_t DlMallocSpace::bitmap_index_ = 0;
@@ -103,15 +130,15 @@ DlMallocSpace::DlMallocSpace(const std::string& name, MemMap* mem_map, void* msp
size_t bitmap_index = bitmap_index_++;
- static const uintptr_t kGcCardSize = static_cast<uintptr_t>(CardTable::kCardSize);
+ static const uintptr_t kGcCardSize = static_cast<uintptr_t>(accounting::CardTable::kCardSize);
CHECK(reinterpret_cast<uintptr_t>(mem_map->Begin()) % kGcCardSize == 0);
CHECK(reinterpret_cast<uintptr_t>(mem_map->End()) % kGcCardSize == 0);
- live_bitmap_.reset(SpaceBitmap::Create(
+ live_bitmap_.reset(accounting::SpaceBitmap::Create(
StringPrintf("allocspace %s live-bitmap %d", name.c_str(), static_cast<int>(bitmap_index)),
Begin(), Capacity()));
DCHECK(live_bitmap_.get() != NULL) << "could not create allocspace live bitmap #" << bitmap_index;
- mark_bitmap_.reset(SpaceBitmap::Create(
+ mark_bitmap_.reset(accounting::SpaceBitmap::Create(
StringPrintf("allocspace %s mark-bitmap %d", name.c_str(), static_cast<int>(bitmap_index)),
Begin(), Capacity()));
DCHECK(live_bitmap_.get() != NULL) << "could not create allocspace mark bitmap #" << bitmap_index;
@@ -177,8 +204,13 @@ DlMallocSpace* DlMallocSpace::Create(const std::string& name, size_t initial_siz
// Everything is set so record in immutable structure and leave
MemMap* mem_map_ptr = mem_map.release();
- DlMallocSpace* space = new DlMallocSpace(name, mem_map_ptr, mspace, mem_map_ptr->Begin(), end,
- growth_limit);
+ DlMallocSpace* space;
+ if (RUNNING_ON_VALGRIND > 0) {
+ space = new ValgrindDlMallocSpace(name, mem_map_ptr, mspace, mem_map_ptr->Begin(), end,
+ growth_limit);
+ } else {
+ space = new DlMallocSpace(name, mem_map_ptr, mspace, mem_map_ptr->Begin(), end, growth_limit);
+ }
if (VLOG_IS_ON(heap) || VLOG_IS_ON(startup)) {
LOG(INFO) << "Space::CreateAllocSpace exiting (" << PrettyDuration(NanoTime() - start_time)
<< " ) " << *space;
@@ -203,33 +235,26 @@ void* DlMallocSpace::CreateMallocSpace(void* begin, size_t morecore_start, size_
}
void DlMallocSpace::SwapBitmaps() {
- SpaceBitmap* temp_live_bitmap = live_bitmap_.release();
- live_bitmap_.reset(mark_bitmap_.release());
- mark_bitmap_.reset(temp_live_bitmap);
+ live_bitmap_.swap(mark_bitmap_);
// Swap names to get more descriptive diagnostics.
- std::string temp_name = live_bitmap_->GetName();
+ std::string temp_name(live_bitmap_->GetName());
live_bitmap_->SetName(mark_bitmap_->GetName());
mark_bitmap_->SetName(temp_name);
}
mirror::Object* DlMallocSpace::AllocWithoutGrowthLocked(size_t num_bytes) {
- if (kDebugSpaces) {
- num_bytes += sizeof(word);
- }
-
mirror::Object* result = reinterpret_cast<mirror::Object*>(mspace_calloc(mspace_, 1, num_bytes));
- if (kDebugSpaces && result != NULL) {
- CHECK(Contains(result)) << "Allocation (" << reinterpret_cast<void*>(result)
- << ") not in bounds of allocation space " << *this;
- // Put a magic pattern before and after the allocation.
- *reinterpret_cast<word*>(reinterpret_cast<byte*>(result) + AllocationSize(result)
- - sizeof(word) - kChunkOverhead) = kPaddingValue;
+ if (result != NULL) {
+ if (kDebugSpaces) {
+ CHECK(Contains(result)) << "Allocation (" << reinterpret_cast<void*>(result)
+ << ") not in bounds of allocation space " << *this;
+ }
+ size_t allocation_size = AllocationSize(result);
+ num_bytes_allocated_ += allocation_size;
+ total_bytes_allocated_ += allocation_size;
+ ++total_objects_allocated_;
+ ++num_objects_allocated_;
}
- size_t allocation_size = AllocationSize(result);
- num_bytes_allocated_ += allocation_size;
- total_bytes_allocated_ += allocation_size;
- ++total_objects_allocated_;
- ++num_objects_allocated_;
return result;
}
@@ -263,8 +288,8 @@ void DlMallocSpace::SetGrowthLimit(size_t growth_limit) {
DlMallocSpace* DlMallocSpace::CreateZygoteSpace() {
end_ = reinterpret_cast<byte*>(RoundUp(reinterpret_cast<uintptr_t>(end_), kPageSize));
- DCHECK(IsAligned<CardTable::kCardSize>(begin_));
- DCHECK(IsAligned<CardTable::kCardSize>(end_));
+ DCHECK(IsAligned<accounting::CardTable::kCardSize>(begin_));
+ DCHECK(IsAligned<accounting::CardTable::kCardSize>(end_));
DCHECK(IsAligned<kPageSize>(begin_));
DCHECK(IsAligned<kPageSize>(end_));
size_t size = RoundUp(Size(), kPageSize);
@@ -291,7 +316,7 @@ DlMallocSpace* DlMallocSpace::CreateZygoteSpace() {
VLOG(heap) << "Size " << GetMemMap()->Size();
VLOG(heap) << "GrowthLimit " << PrettySize(growth_limit);
VLOG(heap) << "Capacity " << PrettySize(capacity);
- UniquePtr<MemMap> mem_map(MemMap::MapAnonymous(GetName().c_str(), End(), capacity, PROT_READ | PROT_WRITE));
+ UniquePtr<MemMap> mem_map(MemMap::MapAnonymous(GetName(), End(), capacity, PROT_READ | PROT_WRITE));
void* mspace = CreateMallocSpace(end_, starting_size, initial_size);
// Protect memory beyond the initial size.
byte* end = mem_map->Begin() + starting_size;
@@ -314,9 +339,6 @@ size_t DlMallocSpace::Free(Thread* self, mirror::Object* ptr) {
if (kDebugSpaces) {
CHECK(ptr != NULL);
CHECK(Contains(ptr)) << "Free (" << ptr << ") not in bounds of heap " << *this;
- CHECK_EQ(
- *reinterpret_cast<word*>(reinterpret_cast<byte*>(ptr) + AllocationSize(ptr) -
- sizeof(word) - kChunkOverhead), kPaddingValue);
}
const size_t bytes_freed = InternalAllocationSize(ptr);
num_bytes_allocated_ -= bytes_freed;
@@ -374,20 +396,16 @@ void* DlMallocSpace::MoreCore(intptr_t increment) {
lock_.AssertHeld(Thread::Current());
byte* original_end = end_;
if (increment != 0) {
- VLOG(heap) << "AllocSpace::MoreCore " << PrettySize(increment);
+ VLOG(heap) << "DlMallocSpace::MoreCore " << PrettySize(increment);
byte* new_end = original_end + increment;
if (increment > 0) {
-#if DEBUG_SPACES
// Should never be asked to increase the allocation beyond the capacity of the space. Enforced
// by mspace_set_footprint_limit.
CHECK_LE(new_end, Begin() + Capacity());
-#endif
CHECK_MEMORY_CALL(mprotect, (original_end, increment, PROT_READ | PROT_WRITE), GetName());
} else {
-#if DEBUG_SPACES
// Should never be asked for negative footprint (ie before begin)
CHECK_GT(original_end + increment, Begin());
-#endif
// Advise we don't need the pages and protect them
// TODO: by removing permissions to the pages we may be causing TLB shoot-down which can be
// expensive (note the same isn't true for giving permissions to a page as the protected
@@ -414,29 +432,13 @@ size_t DlMallocSpace::AllocationSize(const mirror::Object* obj) {
return InternalAllocationSize(obj);
}
-void MspaceMadviseCallback(void* start, void* end, size_t used_bytes, void* arg) {
- // Is this chunk in use?
- if (used_bytes != 0) {
- return;
- }
- // Do we have any whole pages to give back?
- start = reinterpret_cast<void*>(RoundUp(reinterpret_cast<uintptr_t>(start), kPageSize));
- end = reinterpret_cast<void*>(RoundDown(reinterpret_cast<uintptr_t>(end), kPageSize));
- if (end > start) {
- size_t length = reinterpret_cast<byte*>(end) - reinterpret_cast<byte*>(start);
- CHECK_MEMORY_CALL(madvise, (start, length, MADV_DONTNEED), "trim");
- size_t* reclaimed = reinterpret_cast<size_t*>(arg);
- *reclaimed += length;
- }
-}
-
size_t DlMallocSpace::Trim() {
MutexLock mu(Thread::Current(), lock_);
// Trim to release memory at the end of the space.
mspace_trim(mspace_, 0);
// Visit space looking for page-sized holes to advise the kernel we don't need.
size_t reclaimed = 0;
- mspace_inspect_all(mspace_, MspaceMadviseCallback, &reclaimed);
+ mspace_inspect_all(mspace_, DlmallocMadviseCallback, &reclaimed);
return reclaimed;
}
@@ -465,111 +467,14 @@ void DlMallocSpace::SetFootprintLimit(size_t new_size) {
mspace_set_footprint_limit(mspace_, new_size);
}
-size_t ImageSpace::bitmap_index_ = 0;
-
-ImageSpace::ImageSpace(const std::string& name, MemMap* mem_map)
- : MemMapSpace(name, mem_map, mem_map->Size(), kGcRetentionPolicyNeverCollect) {
- const size_t bitmap_index = bitmap_index_++;
- live_bitmap_.reset(SpaceBitmap::Create(
- StringPrintf("imagespace %s live-bitmap %d", name.c_str(), static_cast<int>(bitmap_index)),
- Begin(), Capacity()));
- DCHECK(live_bitmap_.get() != NULL) << "could not create imagespace live bitmap #" << bitmap_index;
-}
-
-ImageSpace* ImageSpace::Create(const std::string& image_file_name) {
- CHECK(!image_file_name.empty());
-
- uint64_t start_time = 0;
- if (VLOG_IS_ON(heap) || VLOG_IS_ON(startup)) {
- start_time = NanoTime();
- LOG(INFO) << "Space::CreateImageSpace entering" << " image_file_name=" << image_file_name;
- }
-
- UniquePtr<File> file(OS::OpenFile(image_file_name.c_str(), false));
- if (file.get() == NULL) {
- LOG(ERROR) << "Failed to open " << image_file_name;
- return NULL;
- }
- ImageHeader image_header;
- bool success = file->ReadFully(&image_header, sizeof(image_header));
- if (!success || !image_header.IsValid()) {
- LOG(ERROR) << "Invalid image header " << image_file_name;
- return NULL;
- }
- UniquePtr<MemMap> map(MemMap::MapFileAtAddress(image_header.GetImageBegin(),
- file->GetLength(),
- PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_FIXED,
- file->Fd(),
- 0,
- false));
- if (map.get() == NULL) {
- LOG(ERROR) << "Failed to map " << image_file_name;
- return NULL;
- }
- CHECK_EQ(image_header.GetImageBegin(), map->Begin());
- DCHECK_EQ(0, memcmp(&image_header, map->Begin(), sizeof(ImageHeader)));
-
- Runtime* runtime = Runtime::Current();
- mirror::Object* resolution_method = image_header.GetImageRoot(ImageHeader::kResolutionMethod);
- runtime->SetResolutionMethod(down_cast<mirror::AbstractMethod*>(resolution_method));
-
- mirror::Object* callee_save_method = image_header.GetImageRoot(ImageHeader::kCalleeSaveMethod);
- runtime->SetCalleeSaveMethod(down_cast<mirror::AbstractMethod*>(callee_save_method), Runtime::kSaveAll);
- callee_save_method = image_header.GetImageRoot(ImageHeader::kRefsOnlySaveMethod);
- runtime->SetCalleeSaveMethod(down_cast<mirror::AbstractMethod*>(callee_save_method), Runtime::kRefsOnly);
- callee_save_method = image_header.GetImageRoot(ImageHeader::kRefsAndArgsSaveMethod);
- runtime->SetCalleeSaveMethod(down_cast<mirror::AbstractMethod*>(callee_save_method), Runtime::kRefsAndArgs);
-
- ImageSpace* space = new ImageSpace(image_file_name, map.release());
- if (VLOG_IS_ON(heap) || VLOG_IS_ON(startup)) {
- LOG(INFO) << "Space::CreateImageSpace exiting (" << PrettyDuration(NanoTime() - start_time)
- << ") " << *space;
- }
- return space;
-}
-
-void ImageSpace::RecordImageAllocations(SpaceBitmap* live_bitmap) const {
- uint64_t start_time = 0;
- if (VLOG_IS_ON(heap) || VLOG_IS_ON(startup)) {
- LOG(INFO) << "ImageSpace::RecordImageAllocations entering";
- start_time = NanoTime();
- }
- DCHECK(!Runtime::Current()->IsStarted());
- CHECK(live_bitmap != NULL);
- byte* current = Begin() + RoundUp(sizeof(ImageHeader), kObjectAlignment);
- byte* end = End();
- while (current < end) {
- DCHECK_ALIGNED(current, kObjectAlignment);
- const mirror::Object* obj = reinterpret_cast<const mirror::Object*>(current);
- live_bitmap->Set(obj);
- current += RoundUp(obj->SizeOf(), kObjectAlignment);
- }
- if (VLOG_IS_ON(heap) || VLOG_IS_ON(startup)) {
- LOG(INFO) << "ImageSpace::RecordImageAllocations exiting ("
- << PrettyDuration(NanoTime() - start_time) << ")";
- }
-}
-
-std::ostream& operator<<(std::ostream& os, const Space& space) {
- space.Dump(os);
- return os;
-}
-
void DlMallocSpace::Dump(std::ostream& os) const {
os << GetType()
- << "begin=" << reinterpret_cast<void*>(Begin())
+ << " begin=" << reinterpret_cast<void*>(Begin())
<< ",end=" << reinterpret_cast<void*>(End())
<< ",size=" << PrettySize(Size()) << ",capacity=" << PrettySize(Capacity())
<< ",name=\"" << GetName() << "\"]";
}
-void ImageSpace::Dump(std::ostream& os) const {
- os << GetType()
- << "begin=" << reinterpret_cast<void*>(Begin())
- << ",end=" << reinterpret_cast<void*>(End())
- << ",size=" << PrettySize(Size())
- << ",name=\"" << GetName() << "\"]";
-}
-
+} // namespace space
+} // namespace gc
} // namespace art
diff --git a/src/gc/space/dlmalloc_space.h b/src/gc/space/dlmalloc_space.h
new file mode 100644
index 0000000000..00df0e6d42
--- /dev/null
+++ b/src/gc/space/dlmalloc_space.h
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2011 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_GC_SPACE_DLMALLOC_SPACE_H_
+#define ART_SRC_GC_SPACE_DLMALLOC_SPACE_H_
+
+#include "gc/allocator/dlmalloc.h"
+#include "space.h"
+
+namespace art {
+namespace gc {
+
+namespace collector {
+ class MarkSweep;
+} // namespace collector
+
+namespace space {
+
+// An alloc space is a space where objects may be allocated and garbage collected.
+class DlMallocSpace : public MemMapSpace, public AllocSpace {
+ public:
+ typedef void(*WalkCallback)(void *start, void *end, size_t num_bytes, void* callback_arg);
+
+ SpaceType GetType() const {
+ if (GetGcRetentionPolicy() == kGcRetentionPolicyFullCollect) {
+ return kSpaceTypeZygoteSpace;
+ } else {
+ return kSpaceTypeAllocSpace;
+ }
+ }
+
+ // Create a AllocSpace with the requested sizes. The requested
+ // base address is not guaranteed to be granted, if it is required,
+ // the caller should call Begin on the returned space to confirm
+ // the request was granted.
+ static DlMallocSpace* Create(const std::string& name, size_t initial_size, size_t growth_limit,
+ size_t capacity, byte* requested_begin);
+
+ // Allocate num_bytes without allowing the underlying mspace to grow.
+ virtual mirror::Object* AllocWithGrowth(Thread* self, size_t num_bytes);
+
+ // Allocate num_bytes allowing the underlying mspace to grow.
+ virtual mirror::Object* Alloc(Thread* self, size_t num_bytes);
+
+ // Return the storage space required by obj.
+ virtual size_t AllocationSize(const mirror::Object* obj);
+ virtual size_t Free(Thread* self, mirror::Object* ptr);
+ virtual size_t FreeList(Thread* self, size_t num_ptrs, mirror::Object** ptrs);
+
+ void* MoreCore(intptr_t increment);
+
+ void* GetMspace() const {
+ return mspace_;
+ }
+
+ // Hands unused pages back to the system.
+ size_t Trim();
+
+ // Perform a mspace_inspect_all which calls back for each allocation chunk. The chunk may not be
+ // in use, indicated by num_bytes equaling zero.
+ void Walk(WalkCallback callback, void* arg);
+
+ // Returns the number of bytes that the heap is allowed to obtain from the system via MoreCore.
+ size_t GetFootprintLimit();
+
+ // Set the maximum number of bytes that the heap is allowed to obtain from the system via
+ // MoreCore. Note this is used to stop the mspace growing beyond the limit to Capacity. When
+ // allocations fail we GC before increasing the footprint limit and allowing the mspace to grow.
+ void SetFootprintLimit(size_t limit);
+
+ // Removes the fork time growth limit on capacity, allowing the application to allocate up to the
+ // maximum reserved size of the heap.
+ void ClearGrowthLimit() {
+ growth_limit_ = NonGrowthLimitCapacity();
+ }
+
+ // Override capacity so that we only return the possibly limited capacity
+ size_t Capacity() const {
+ return growth_limit_;
+ }
+
+ // The total amount of memory reserved for the alloc space.
+ size_t NonGrowthLimitCapacity() const {
+ return GetMemMap()->Size();
+ }
+
+ accounting::SpaceBitmap* GetLiveBitmap() const {
+ return live_bitmap_.get();
+ }
+
+ accounting::SpaceBitmap* GetMarkBitmap() const {
+ return mark_bitmap_.get();
+ }
+
+ void Dump(std::ostream& os) const;
+
+ void SetGrowthLimit(size_t growth_limit);
+
+ // Swap the live and mark bitmaps of this space. This is used by the GC for concurrent sweeping.
+ void SwapBitmaps();
+
+ // Turn ourself into a zygote space and return a new alloc space which has our unused memory.
+ DlMallocSpace* CreateZygoteSpace();
+
+ uint64_t GetBytesAllocated() const {
+ return num_bytes_allocated_;
+ }
+
+ uint64_t GetObjectsAllocated() const {
+ return num_objects_allocated_;
+ }
+
+ uint64_t GetTotalBytesAllocated() const {
+ return total_bytes_allocated_;
+ }
+
+ uint64_t GetTotalObjectsAllocated() const {
+ return total_objects_allocated_;
+ }
+
+ protected:
+ DlMallocSpace(const std::string& name, MemMap* mem_map, void* mspace, byte* begin, byte* end,
+ size_t growth_limit);
+
+ private:
+ size_t InternalAllocationSize(const mirror::Object* obj);
+ mirror::Object* AllocWithoutGrowthLocked(size_t num_bytes) EXCLUSIVE_LOCKS_REQUIRED(lock_);
+
+ bool Init(size_t initial_size, size_t maximum_size, size_t growth_size, byte* requested_base);
+
+ static void* CreateMallocSpace(void* base, size_t morecore_start, size_t initial_size);
+
+ UniquePtr<accounting::SpaceBitmap> live_bitmap_;
+ UniquePtr<accounting::SpaceBitmap> mark_bitmap_;
+ UniquePtr<accounting::SpaceBitmap> temp_bitmap_;
+
+ // Approximate number of bytes which have been allocated into the space.
+ size_t num_bytes_allocated_;
+ size_t num_objects_allocated_;
+ size_t total_bytes_allocated_;
+ size_t total_objects_allocated_;
+
+ static size_t bitmap_index_;
+
+ // The boundary tag overhead.
+ static const size_t kChunkOverhead = kWordSize;
+
+ // Used to ensure mutual exclusion when the allocation spaces data structures are being modified.
+ Mutex lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
+
+ // Underlying malloc space
+ void* const mspace_;
+
+ // The capacity of the alloc space until such time that ClearGrowthLimit is called.
+ // The underlying mem_map_ controls the maximum size we allow the heap to grow to. The growth
+ // limit is a value <= to the mem_map_ capacity used for ergonomic reasons because of the zygote.
+ // Prior to forking the zygote the heap will have a maximally sized mem_map_ but the growth_limit_
+ // will be set to a lower value. The growth_limit_ is used as the capacity of the alloc_space_,
+ // however, capacity normally can't vary. In the case of the growth_limit_ it can be cleared
+ // one time by a call to ClearGrowthLimit.
+ size_t growth_limit_;
+
+ friend class collector::MarkSweep;
+
+ DISALLOW_COPY_AND_ASSIGN(DlMallocSpace);
+};
+
+} // namespace space
+} // namespace gc
+} // namespace art
+
+#endif // ART_SRC_GC_SPACE_DLMALLOC_SPACE_H_
diff --git a/src/gc/space/image_space.cc b/src/gc/space/image_space.cc
new file mode 100644
index 0000000000..46c39378d7
--- /dev/null
+++ b/src/gc/space/image_space.cc
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2011 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 "image_space.h"
+
+#include "base/unix_file/fd_file.h"
+#include "gc/accounting/space_bitmap-inl.h"
+#include "mirror/abstract_method.h"
+#include "mirror/class-inl.h"
+#include "mirror/object-inl.h"
+#include "os.h"
+#include "runtime.h"
+#include "space-inl.h"
+#include "utils.h"
+
+namespace art {
+namespace gc {
+namespace space {
+
+size_t ImageSpace::bitmap_index_ = 0;
+
+ImageSpace::ImageSpace(const std::string& name, MemMap* mem_map)
+: MemMapSpace(name, mem_map, mem_map->Size(), kGcRetentionPolicyNeverCollect) {
+ const size_t bitmap_index = bitmap_index_++;
+ live_bitmap_.reset(accounting::SpaceBitmap::Create(
+ StringPrintf("imagespace %s live-bitmap %d", name.c_str(), static_cast<int>(bitmap_index)),
+ Begin(), Capacity()));
+ DCHECK(live_bitmap_.get() != NULL) << "could not create imagespace live bitmap #" << bitmap_index;
+}
+
+ImageSpace* ImageSpace::Create(const std::string& image_file_name) {
+ CHECK(!image_file_name.empty());
+
+ uint64_t start_time = 0;
+ if (VLOG_IS_ON(heap) || VLOG_IS_ON(startup)) {
+ start_time = NanoTime();
+ LOG(INFO) << "Space::CreateImageSpace entering" << " image_file_name=" << image_file_name;
+ }
+
+ UniquePtr<File> file(OS::OpenFile(image_file_name.c_str(), false));
+ if (file.get() == NULL) {
+ LOG(ERROR) << "Failed to open " << image_file_name;
+ return NULL;
+ }
+ ImageHeader image_header;
+ bool success = file->ReadFully(&image_header, sizeof(image_header));
+ if (!success || !image_header.IsValid()) {
+ LOG(ERROR) << "Invalid image header " << image_file_name;
+ return NULL;
+ }
+ UniquePtr<MemMap> map(MemMap::MapFileAtAddress(image_header.GetImageBegin(),
+ file->GetLength(),
+ PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_FIXED,
+ file->Fd(),
+ 0,
+ false));
+ if (map.get() == NULL) {
+ LOG(ERROR) << "Failed to map " << image_file_name;
+ return NULL;
+ }
+ CHECK_EQ(image_header.GetImageBegin(), map->Begin());
+ DCHECK_EQ(0, memcmp(&image_header, map->Begin(), sizeof(ImageHeader)));
+
+ Runtime* runtime = Runtime::Current();
+ mirror::Object* resolution_method = image_header.GetImageRoot(ImageHeader::kResolutionMethod);
+ runtime->SetResolutionMethod(down_cast<mirror::AbstractMethod*>(resolution_method));
+
+ mirror::Object* callee_save_method = image_header.GetImageRoot(ImageHeader::kCalleeSaveMethod);
+ runtime->SetCalleeSaveMethod(down_cast<mirror::AbstractMethod*>(callee_save_method), Runtime::kSaveAll);
+ callee_save_method = image_header.GetImageRoot(ImageHeader::kRefsOnlySaveMethod);
+ runtime->SetCalleeSaveMethod(down_cast<mirror::AbstractMethod*>(callee_save_method), Runtime::kRefsOnly);
+ callee_save_method = image_header.GetImageRoot(ImageHeader::kRefsAndArgsSaveMethod);
+ runtime->SetCalleeSaveMethod(down_cast<mirror::AbstractMethod*>(callee_save_method), Runtime::kRefsAndArgs);
+
+ ImageSpace* space = new ImageSpace(image_file_name, map.release());
+ if (VLOG_IS_ON(heap) || VLOG_IS_ON(startup)) {
+ LOG(INFO) << "Space::CreateImageSpace exiting (" << PrettyDuration(NanoTime() - start_time)
+ << ") " << *space;
+ }
+ return space;
+}
+
+void ImageSpace::RecordImageAllocations(accounting::SpaceBitmap* live_bitmap) const {
+ uint64_t start_time = 0;
+ if (VLOG_IS_ON(heap) || VLOG_IS_ON(startup)) {
+ LOG(INFO) << "ImageSpace::RecordImageAllocations entering";
+ start_time = NanoTime();
+ }
+ DCHECK(!Runtime::Current()->IsStarted());
+ CHECK(live_bitmap != NULL);
+ byte* current = Begin() + RoundUp(sizeof(ImageHeader), kObjectAlignment);
+ byte* end = End();
+ while (current < end) {
+ DCHECK_ALIGNED(current, kObjectAlignment);
+ const mirror::Object* obj = reinterpret_cast<const mirror::Object*>(current);
+ live_bitmap->Set(obj);
+ current += RoundUp(obj->SizeOf(), kObjectAlignment);
+ }
+ if (VLOG_IS_ON(heap) || VLOG_IS_ON(startup)) {
+ LOG(INFO) << "ImageSpace::RecordImageAllocations exiting ("
+ << PrettyDuration(NanoTime() - start_time) << ")";
+ }
+}
+
+void ImageSpace::Dump(std::ostream& os) const {
+ os << GetType()
+ << "begin=" << reinterpret_cast<void*>(Begin())
+ << ",end=" << reinterpret_cast<void*>(End())
+ << ",size=" << PrettySize(Size())
+ << ",name=\"" << GetName() << "\"]";
+}
+
+} // namespace space
+} // namespace gc
+} // namespace art
diff --git a/src/gc/space/image_space.h b/src/gc/space/image_space.h
new file mode 100644
index 0000000000..afec5b7305
--- /dev/null
+++ b/src/gc/space/image_space.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2011 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_GC_SPACE_IMAGE_SPACE_H_
+#define ART_SRC_GC_SPACE_IMAGE_SPACE_H_
+
+#include "space.h"
+
+namespace art {
+namespace gc {
+namespace space {
+
+// An image space is a space backed with a memory mapped image.
+class ImageSpace : public MemMapSpace {
+ public:
+ bool CanAllocateInto() const {
+ return false;
+ }
+
+ SpaceType GetType() const {
+ return kSpaceTypeImageSpace;
+ }
+
+ // create a Space from an image file. cannot be used for future allocation or collected.
+ static ImageSpace* Create(const std::string& image)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ const ImageHeader& GetImageHeader() const {
+ return *reinterpret_cast<ImageHeader*>(Begin());
+ }
+
+ const std::string GetImageFilename() const {
+ return GetName();
+ }
+
+ // Mark the objects defined in this space in the given live bitmap
+ void RecordImageAllocations(accounting::SpaceBitmap* live_bitmap) const
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ accounting::SpaceBitmap* GetLiveBitmap() const {
+ return live_bitmap_.get();
+ }
+
+ accounting::SpaceBitmap* GetMarkBitmap() const {
+ // ImageSpaces have the same bitmap for both live and marked. This helps reduce the number of
+ // special cases to test against.
+ return live_bitmap_.get();
+ }
+
+ void Dump(std::ostream& os) const;
+
+ private:
+ friend class Space;
+
+ static size_t bitmap_index_;
+
+ UniquePtr<accounting::SpaceBitmap> live_bitmap_;
+
+ ImageSpace(const std::string& name, MemMap* mem_map);
+
+ DISALLOW_COPY_AND_ASSIGN(ImageSpace);
+};
+
+} // namespace space
+} // namespace gc
+} // namespace art
+
+#endif // ART_SRC_GC_SPACE_IMAGE_SPACE_H_
diff --git a/src/gc/large_object_space.cc b/src/gc/space/large_object_space.cc
index c3bf3824ad..3cee1b7355 100644
--- a/src/gc/large_object_space.cc
+++ b/src/gc/space/large_object_space.cc
@@ -14,18 +14,19 @@
* limitations under the License.
*/
+#include "large_object_space.h"
+
#include "base/logging.h"
#include "base/stl_util.h"
-#include "large_object_space.h"
#include "UniquePtr.h"
-#include "dlmalloc.h"
#include "image.h"
#include "os.h"
-#include "space_bitmap.h"
#include "thread.h"
#include "utils.h"
namespace art {
+namespace gc {
+namespace space {
void LargeObjectSpace::SwapBitmaps() {
live_objects_.swap(mark_objects_);
@@ -39,8 +40,6 @@ LargeObjectSpace::LargeObjectSpace(const std::string& name)
: DiscontinuousSpace(name, kGcRetentionPolicyAlwaysCollect),
num_bytes_allocated_(0), num_objects_allocated_(0), total_bytes_allocated_(0),
total_objects_allocated_(0) {
- live_objects_.reset(new SpaceSetMap("large live objects"));
- mark_objects_.reset(new SpaceSetMap("large marked objects"));
}
@@ -281,4 +280,6 @@ void FreeListSpace::Dump(std::ostream& os) const{
<< " end: " << reinterpret_cast<void*>(End());
}
-}
+} // namespace space
+} // namespace gc
+} // namespace art
diff --git a/src/gc/large_object_space.h b/src/gc/space/large_object_space.h
index 8a2f9707fd..197fad3854 100644
--- a/src/gc/large_object_space.h
+++ b/src/gc/space/large_object_space.h
@@ -14,51 +14,38 @@
* limitations under the License.
*/
-#ifndef ART_SRC_GC_LARGE_OBJECT_SPACE_H_
-#define ART_SRC_GC_LARGE_OBJECT_SPACE_H_
+#ifndef ART_SRC_GC_SPACE_LARGE_OBJECT_SPACE_H_
+#define ART_SRC_GC_SPACE_LARGE_OBJECT_SPACE_H_
-#include "space.h"
+
+#include "dlmalloc_space.h"
#include "safe_map.h"
+#include "space.h"
#include <set>
#include <vector>
namespace art {
-class SpaceSetMap;
+namespace gc {
+namespace space {
// Abstraction implemented by all large object spaces.
class LargeObjectSpace : public DiscontinuousSpace, public AllocSpace {
public:
- virtual bool CanAllocateInto() const {
- return true;
- }
-
- virtual bool IsCompactible() const {
- return true;
- }
-
virtual SpaceType GetType() const {
return kSpaceTypeLargeObjectSpace;
}
- virtual SpaceSetMap* GetLiveObjects() const {
- return live_objects_.get();
- }
-
- virtual SpaceSetMap* GetMarkObjects() const {
- return mark_objects_.get();
- }
-
virtual void SwapBitmaps();
virtual void CopyLiveToMarked();
virtual void Walk(DlMallocSpace::WalkCallback, void* arg) = 0;
virtual ~LargeObjectSpace() {}
- uint64_t GetNumBytesAllocated() const {
+ uint64_t GetBytesAllocated() const {
return num_bytes_allocated_;
}
- uint64_t GetNumObjectsAllocated() const {
+ uint64_t GetObjectsAllocated() const {
return num_objects_allocated_;
}
@@ -82,10 +69,10 @@ class LargeObjectSpace : public DiscontinuousSpace, public AllocSpace {
size_t total_bytes_allocated_;
size_t total_objects_allocated_;
- UniquePtr<SpaceSetMap> live_objects_;
- UniquePtr<SpaceSetMap> mark_objects_;
-
friend class Space;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(LargeObjectSpace);
};
// A discontinuous large object space implemented by individual mmap/munmap calls.
@@ -96,12 +83,13 @@ class LargeObjectMapSpace : public LargeObjectSpace {
static LargeObjectMapSpace* Create(const std::string& name);
// Return the storage space required by obj.
- virtual size_t AllocationSize(const mirror::Object* obj);
- virtual mirror::Object* Alloc(Thread* self, size_t num_bytes);
+ size_t AllocationSize(const mirror::Object* obj);
+ mirror::Object* Alloc(Thread* self, size_t num_bytes);
size_t Free(Thread* self, mirror::Object* ptr);
- virtual void Walk(DlMallocSpace::WalkCallback, void* arg);
+ void Walk(DlMallocSpace::WalkCallback, void* arg);
// TODO: disabling thread safety analysis as this may be called when we already hold lock_.
- virtual bool Contains(const mirror::Object* obj) const NO_THREAD_SAFETY_ANALYSIS;
+ bool Contains(const mirror::Object* obj) const NO_THREAD_SAFETY_ANALYSIS;
+
private:
LargeObjectMapSpace(const std::string& name);
virtual ~LargeObjectMapSpace() {}
@@ -114,6 +102,7 @@ private:
};
// A continuous large object space with a free-list to handle holes.
+// TODO: this implementation is buggy.
class FreeListSpace : public LargeObjectSpace {
public:
virtual ~FreeListSpace();
@@ -140,7 +129,7 @@ class FreeListSpace : public LargeObjectSpace {
return End() - Begin();
}
- virtual void Dump(std::ostream& os) const;
+ void Dump(std::ostream& os) const;
private:
static const size_t kAlignment = kPageSize;
@@ -197,6 +186,8 @@ class FreeListSpace : public LargeObjectSpace {
FreeChunks free_chunks_ GUARDED_BY(lock_);
};
-}
+} // namespace space
+} // namespace gc
+} // namespace art
-#endif // ART_SRC_GC_LARGE_OBJECT_SPACE_H_
+#endif // ART_SRC_GC_SPACE_LARGE_OBJECT_SPACE_H_
diff --git a/src/gc/space/space-inl.h b/src/gc/space/space-inl.h
new file mode 100644
index 0000000000..8216d1b075
--- /dev/null
+++ b/src/gc/space/space-inl.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2011 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_GC_SPACE_SPACE_INL_H_
+#define ART_SRC_GC_SPACE_SPACE_INL_H_
+
+#include "space.h"
+
+#include "dlmalloc_space.h"
+#include "image_space.h"
+
+namespace art {
+namespace gc {
+namespace space {
+
+inline ImageSpace* Space::AsImageSpace() {
+ DCHECK_EQ(GetType(), kSpaceTypeImageSpace);
+ return down_cast<ImageSpace*>(down_cast<MemMapSpace*>(this));
+}
+
+inline DlMallocSpace* Space::AsDlMallocSpace() {
+ DCHECK_EQ(GetType(), kSpaceTypeAllocSpace);
+ return down_cast<DlMallocSpace*>(down_cast<MemMapSpace*>(this));
+}
+
+inline DlMallocSpace* Space::AsZygoteSpace() {
+ DCHECK_EQ(GetType(), kSpaceTypeZygoteSpace);
+ return down_cast<DlMallocSpace*>(down_cast<MemMapSpace*>(this));
+}
+
+inline LargeObjectSpace* Space::AsLargeObjectSpace() {
+ DCHECK_EQ(GetType(), kSpaceTypeLargeObjectSpace);
+ return reinterpret_cast<LargeObjectSpace*>(this);
+}
+
+} // namespace space
+} // namespace gc
+} // namespace art
+
+#endif // ART_SRC_GC_SPACE_SPACE_INL_H_
diff --git a/src/gc/space/space.cc b/src/gc/space/space.cc
new file mode 100644
index 0000000000..eae281ad40
--- /dev/null
+++ b/src/gc/space/space.cc
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2011 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 "space.h"
+
+#include "base/logging.h"
+
+namespace art {
+namespace gc {
+namespace space {
+
+Space::Space(const std::string& name, GcRetentionPolicy gc_retention_policy) :
+ name_(name), gc_retention_policy_(gc_retention_policy) { }
+
+void Space::Dump(std::ostream& os) const {
+ os << GetName() << ":" << GetGcRetentionPolicy();
+}
+
+std::ostream& operator<<(std::ostream& os, const Space& space) {
+ space.Dump(os);
+ return os;
+}
+
+
+DiscontinuousSpace::DiscontinuousSpace(const std::string& name,
+ GcRetentionPolicy gc_retention_policy) :
+ Space(name, gc_retention_policy),
+ live_objects_(new accounting::SpaceSetMap("large live objects")),
+ mark_objects_(new accounting::SpaceSetMap("large marked objects")) {
+}
+
+} // namespace space
+} // namespace gc
+} // namespace art
diff --git a/src/gc/space/space.h b/src/gc/space/space.h
new file mode 100644
index 0000000000..ca01c55497
--- /dev/null
+++ b/src/gc/space/space.h
@@ -0,0 +1,295 @@
+/*
+ * Copyright (C) 2011 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_GC_SPACE_SPACE_H_
+#define ART_SRC_GC_SPACE_SPACE_H_
+
+#include <string>
+
+#include "UniquePtr.h"
+#include "base/macros.h"
+#include "base/mutex.h"
+#include "gc/accounting/space_bitmap.h"
+#include "globals.h"
+#include "image.h"
+#include "mem_map.h"
+
+namespace art {
+namespace mirror {
+ class Object;
+} // namespace mirror
+
+namespace gc {
+
+namespace accounting {
+ class SpaceBitmap;
+} // namespace accounting
+
+class Heap;
+
+namespace space {
+
+class DlMallocSpace;
+class ImageSpace;
+class LargeObjectSpace;
+
+static const bool kDebugSpaces = kIsDebugBuild;
+
+// See Space::GetGcRetentionPolicy.
+enum GcRetentionPolicy {
+ // Objects are retained forever with this policy for a space.
+ kGcRetentionPolicyNeverCollect,
+ // Every GC cycle will attempt to collect objects in this space.
+ kGcRetentionPolicyAlwaysCollect,
+ // Objects will be considered for collection only in "full" GC cycles, ie faster partial
+ // collections won't scan these areas such as the Zygote.
+ kGcRetentionPolicyFullCollect,
+};
+std::ostream& operator<<(std::ostream& os, const GcRetentionPolicy& policy);
+
+enum SpaceType {
+ kSpaceTypeImageSpace,
+ kSpaceTypeAllocSpace,
+ kSpaceTypeZygoteSpace,
+ kSpaceTypeLargeObjectSpace,
+};
+std::ostream& operator<<(std::ostream& os, const SpaceType& space_type);
+
+// A space contains memory allocated for managed objects.
+class Space {
+ public:
+ // Dump space. Also key method for C++ vtables.
+ virtual void Dump(std::ostream& os) const;
+
+ // Name of the space. May vary, for example before/after the Zygote fork.
+ const char* GetName() const {
+ return name_.c_str();
+ }
+
+ // The policy of when objects are collected associated with this space.
+ GcRetentionPolicy GetGcRetentionPolicy() const {
+ return gc_retention_policy_;
+ }
+
+ // Does the space support allocation?
+ virtual bool CanAllocateInto() const {
+ return true;
+ }
+
+ // Is the given object contained within this space?
+ virtual bool Contains(const mirror::Object* obj) const = 0;
+
+ // The kind of space this: image, alloc, zygote, large object.
+ virtual SpaceType GetType() const = 0;
+
+ // Is this an image space, ie one backed by a memory mapped image file.
+ bool IsImageSpace() const {
+ return GetType() == kSpaceTypeImageSpace;
+ }
+ ImageSpace* AsImageSpace();
+
+ // Is this a dlmalloc backed allocation space?
+ bool IsDlMallocSpace() const {
+ SpaceType type = GetType();
+ return type == kSpaceTypeAllocSpace || type == kSpaceTypeZygoteSpace;
+ }
+ DlMallocSpace* AsDlMallocSpace();
+
+ // Is this the space allocated into by the Zygote and no-longer in use?
+ bool IsZygoteSpace() const {
+ return GetType() == kSpaceTypeZygoteSpace;
+ }
+ DlMallocSpace* AsZygoteSpace();
+
+ // Does this space hold large objects and implement the large object space abstraction?
+ bool IsLargeObjectSpace() const {
+ return GetType() == kSpaceTypeLargeObjectSpace;
+ }
+ LargeObjectSpace* AsLargeObjectSpace();
+
+ virtual ~Space() {}
+
+ protected:
+ Space(const std::string& name, GcRetentionPolicy gc_retention_policy);
+
+ void SetGcRetentionPolicy(GcRetentionPolicy gc_retention_policy) {
+ gc_retention_policy_ = gc_retention_policy;
+ }
+
+ // Name of the space that may vary due to the Zygote fork.
+ std::string name_;
+
+ private:
+ // When should objects within this space be reclaimed? Not constant as we vary it in the case
+ // of Zygote forking.
+ GcRetentionPolicy gc_retention_policy_;
+
+ friend class art::gc::Heap;
+
+ DISALLOW_COPY_AND_ASSIGN(Space);
+};
+std::ostream& operator<<(std::ostream& os, const Space& space);
+
+// AllocSpace interface.
+class AllocSpace {
+ public:
+ // Number of bytes currently allocated.
+ virtual uint64_t GetBytesAllocated() const = 0;
+ // Number of objects currently allocated.
+ virtual uint64_t GetObjectsAllocated() const = 0;
+ // Number of bytes allocated since the space was created.
+ virtual uint64_t GetTotalBytesAllocated() const = 0;
+ // Number of objects allocated since the space was created.
+ virtual uint64_t GetTotalObjectsAllocated() const = 0;
+
+ // Allocate num_bytes without allowing growth.
+ virtual mirror::Object* Alloc(Thread* self, size_t num_bytes) = 0;
+
+ // Return the storage space required by obj.
+ virtual size_t AllocationSize(const mirror::Object* obj) = 0;
+
+ // Returns how many bytes were freed.
+ virtual size_t Free(Thread* self, mirror::Object* ptr) = 0;
+
+ // Returns how many bytes were freed.
+ virtual size_t FreeList(Thread* self, size_t num_ptrs, mirror::Object** ptrs) = 0;
+
+ protected:
+ AllocSpace() {}
+ virtual ~AllocSpace() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(AllocSpace);
+};
+
+// Continuous spaces have bitmaps, and an address range. Although not required, objects within
+// continuous spaces can be marked in the card table.
+class ContinuousSpace : public Space {
+ public:
+ // Address at which the space begins
+ byte* Begin() const {
+ return begin_;
+ }
+
+ // Address at which the space ends, which may vary as the space is filled.
+ byte* End() const {
+ return end_;
+ }
+
+ // Current size of space
+ size_t Size() const {
+ return End() - Begin();
+ }
+
+ virtual accounting::SpaceBitmap* GetLiveBitmap() const = 0;
+ virtual accounting::SpaceBitmap* GetMarkBitmap() const = 0;
+
+ // Is object within this space? We check to see if the pointer is beyond the end first as
+ // continuous spaces are iterated over from low to high.
+ bool HasAddress(const mirror::Object* obj) const {
+ const byte* byte_ptr = reinterpret_cast<const byte*>(obj);
+ return byte_ptr < End() && byte_ptr >= Begin();
+ }
+
+ bool Contains(const mirror::Object* obj) const {
+ return HasAddress(obj);
+ }
+
+ virtual ~ContinuousSpace() {}
+
+ protected:
+ ContinuousSpace(const std::string& name, GcRetentionPolicy gc_retention_policy,
+ byte* begin, byte* end) :
+ Space(name, gc_retention_policy), begin_(begin), end_(end) {
+ }
+
+
+ // The beginning of the storage for fast access.
+ byte* const begin_;
+
+ // Current end of the space.
+ byte* end_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ContinuousSpace);
+};
+
+// A space where objects may be allocated higgledy-piggledy throughout virtual memory. Currently
+// the card table can't cover these objects and so the write barrier shouldn't be triggered. This
+// is suitable for use for large primitive arrays.
+class DiscontinuousSpace : public Space {
+ public:
+ accounting::SpaceSetMap* GetLiveObjects() const {
+ return live_objects_.get();
+ }
+
+ accounting::SpaceSetMap* GetMarkObjects() const {
+ return mark_objects_.get();
+ }
+
+ virtual ~DiscontinuousSpace() {}
+
+ protected:
+ DiscontinuousSpace(const std::string& name, GcRetentionPolicy gc_retention_policy);
+
+ UniquePtr<accounting::SpaceSetMap> live_objects_;
+ UniquePtr<accounting::SpaceSetMap> mark_objects_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DiscontinuousSpace);
+};
+
+class MemMapSpace : public ContinuousSpace {
+ public:
+ // Maximum which the mapped space can grow to.
+ virtual size_t Capacity() const {
+ return mem_map_->Size();
+ }
+
+ // Size of the space without a limit on its growth. By default this is just the Capacity, but
+ // for the allocation space we support starting with a small heap and then extending it.
+ virtual size_t NonGrowthLimitCapacity() const {
+ return Capacity();
+ }
+
+ protected:
+ MemMapSpace(const std::string& name, MemMap* mem_map, size_t initial_size,
+ GcRetentionPolicy gc_retention_policy)
+ : ContinuousSpace(name, gc_retention_policy,
+ mem_map->Begin(), mem_map->Begin() + initial_size),
+ mem_map_(mem_map) {
+ }
+
+ MemMap* GetMemMap() {
+ return mem_map_.get();
+ }
+
+ const MemMap* GetMemMap() const {
+ return mem_map_.get();
+ }
+
+ private:
+ // Underlying storage of the space
+ UniquePtr<MemMap> mem_map_;
+
+ DISALLOW_COPY_AND_ASSIGN(MemMapSpace);
+};
+
+} // namespace space
+} // namespace gc
+} // namespace art
+
+#endif // ART_SRC_GC_SPACE_SPACE_H_
diff --git a/src/gc/space_test.cc b/src/gc/space/space_test.cc
index 372ec7710c..08ae894e58 100644
--- a/src/gc/space_test.cc
+++ b/src/gc/space/space_test.cc
@@ -14,22 +14,27 @@
* limitations under the License.
*/
-#include "space.h"
+#include "dlmalloc_space.h"
#include "common_test.h"
-#include "dlmalloc.h"
#include "globals.h"
#include "UniquePtr.h"
#include <stdint.h>
namespace art {
+namespace gc {
+namespace space {
class SpaceTest : public CommonTest {
public:
void SizeFootPrintGrowthLimitAndTrimBody(DlMallocSpace* space, intptr_t object_size,
int round, size_t growth_limit);
void SizeFootPrintGrowthLimitAndTrimDriver(size_t object_size);
+
+ void AddContinuousSpace(ContinuousSpace* space) {
+ Runtime::Current()->GetHeap()->AddContinuousSpace(space);
+ }
};
TEST_F(SpaceTest, Init) {
@@ -79,7 +84,7 @@ TEST_F(SpaceTest, ZygoteSpace) {
ASSERT_TRUE(space != NULL);
// Make space findable to the heap, will also delete space when runtime is cleaned up
- Runtime::Current()->GetHeap()->AddSpace(space);
+ AddContinuousSpace(space);
Thread* self = Thread::Current();
// Succeeds, fits without adjusting the footprint limit.
@@ -121,7 +126,7 @@ TEST_F(SpaceTest, ZygoteSpace) {
space = space->CreateZygoteSpace();
// Make space findable to the heap, will also delete space when runtime is cleaned up
- Runtime::Current()->GetHeap()->AddSpace(space);
+ AddContinuousSpace(space);
// Succeeds, fits without adjusting the footprint limit.
ptr1 = space->Alloc(self, 1 * MB);
@@ -148,7 +153,7 @@ TEST_F(SpaceTest, AllocAndFree) {
Thread* self = Thread::Current();
// Make space findable to the heap, will also delete space when runtime is cleaned up
- Runtime::Current()->GetHeap()->AddSpace(space);
+ AddContinuousSpace(space);
// Succeeds, fits without adjusting the footprint limit.
mirror::Object* ptr1 = space->Alloc(self, 1 * MB);
@@ -190,7 +195,7 @@ TEST_F(SpaceTest, AllocAndFreeList) {
ASSERT_TRUE(space != NULL);
// Make space findable to the heap, will also delete space when runtime is cleaned up
- Runtime::Current()->GetHeap()->AddSpace(space);
+ AddContinuousSpace(space);
Thread* self = Thread::Current();
// Succeeds, fits without adjusting the max allowed footprint.
@@ -384,7 +389,7 @@ void SpaceTest::SizeFootPrintGrowthLimitAndTrimDriver(size_t object_size) {
EXPECT_EQ(space->NonGrowthLimitCapacity(), capacity);
// Make space findable to the heap, will also delete space when runtime is cleaned up
- Runtime::Current()->GetHeap()->AddSpace(space);
+ AddContinuousSpace(space);
// In this round we don't allocate with growth and therefore can't grow past the initial size.
// This effectively makes the growth_limit the initial_size, so assert this.
@@ -419,4 +424,6 @@ TEST_SizeFootPrintGrowthLimitAndTrim(1MB, 1 * MB)
TEST_SizeFootPrintGrowthLimitAndTrim(4MB, 4 * MB)
TEST_SizeFootPrintGrowthLimitAndTrim(8MB, 8 * MB)
+} // namespace space
+} // namespace gc
} // namespace art
diff --git a/src/gc/sticky_mark_sweep.cc b/src/gc/sticky_mark_sweep.cc
deleted file mode 100644
index 988d4e79e7..0000000000
--- a/src/gc/sticky_mark_sweep.cc
+++ /dev/null
@@ -1,64 +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 "heap.h"
-#include "large_object_space.h"
-#include "space.h"
-#include "sticky_mark_sweep.h"
-#include "thread.h"
-
-namespace art {
-
-StickyMarkSweep::StickyMarkSweep(Heap* heap, bool is_concurrent)
- : PartialMarkSweep(heap, is_concurrent) {
- cumulative_timings_.SetName(GetName());
-}
-
-StickyMarkSweep::~StickyMarkSweep() {
-
-}
-
-void StickyMarkSweep::BindBitmaps() {
- PartialMarkSweep::BindBitmaps();
-
- Spaces& spaces = GetHeap()->GetSpaces();
- WriterMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_);
- // For sticky GC, we want to bind the bitmaps of both the zygote space and the alloc space.
- // This lets us start with the mark bitmap of the previous garbage collection as the current
- // mark bitmap of the alloc space. After the sticky GC finishes, we then unbind the bitmaps,
- // making it so that the live bitmap of the alloc space is contains the newly marked objects
- // from the sticky GC.
- for (Spaces::iterator it = spaces.begin(); it != spaces.end(); ++it) {
- if ((*it)->GetGcRetentionPolicy() == kGcRetentionPolicyAlwaysCollect) {
- BindLiveToMarkBitmap(*it);
- }
- }
-
- GetHeap()->GetLargeObjectsSpace()->CopyLiveToMarked();
-}
-
-void StickyMarkSweep::MarkReachableObjects() {
- DisableFinger();
- RecursiveMarkDirtyObjects(CardTable::kCardDirty - 1);
-}
-
-void StickyMarkSweep::Sweep(TimingLogger& timings, bool swap_bitmaps) {
- ObjectStack* live_stack = GetHeap()->GetLiveStack();
- SweepArray(timings_, live_stack, false);
- timings_.AddSplit("SweepArray");
-}
-
-} // namespace art
diff --git a/src/hprof/hprof.cc b/src/hprof/hprof.cc
index 7539066c85..d66ec7933b 100644
--- a/src/hprof/hprof.cc
+++ b/src/hprof/hprof.cc
@@ -44,8 +44,10 @@
#include "common_throws.h"
#include "debugger.h"
#include "dex_file-inl.h"
+#include "gc/accounting/heap_bitmap.h"
+#include "gc/heap.h"
+#include "gc/space/space.h"
#include "globals.h"
-#include "heap.h"
#include "mirror/class.h"
#include "mirror/class-inl.h"
#include "mirror/field.h"
@@ -55,7 +57,6 @@
#include "os.h"
#include "safe_map.h"
#include "scoped_thread_state_change.h"
-#include "gc/space.h"
#include "thread_list.h"
namespace art {
@@ -412,7 +413,7 @@ class Hprof {
LOCKS_EXCLUDED(Locks::heap_bitmap_lock_) {
// Walk the roots and the heap.
current_record_.StartNewRecord(body_fp_, HPROF_TAG_HEAP_DUMP_SEGMENT, HPROF_TIME);
- Runtime::Current()->VisitRoots(RootVisitor, this);
+ Runtime::Current()->VisitRoots(RootVisitor, this, false, false);
Thread* self = Thread::Current();
{
WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
diff --git a/src/image_test.cc b/src/image_test.cc
index 8066a90957..9f86a1aedf 100644
--- a/src/image_test.cc
+++ b/src/image_test.cc
@@ -22,7 +22,7 @@
#include "image_writer.h"
#include "oat_writer.h"
#include "signal_catcher.h"
-#include "gc/space.h"
+#include "gc/space/image_space.h"
#include "UniquePtr.h"
#include "utils.h"
#include "vector_output_stream.h"
@@ -43,27 +43,19 @@ TEST_F(ImageTest, WriteRead) {
{
std::vector<uint8_t> oat_contents;
{
+ jobject class_loader = NULL;
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ compiler_driver_->CompileAll(class_loader, class_linker->GetBootClassPath());
+
ScopedObjectAccess soa(Thread::Current());
- std::vector<const DexFile*> dex_files;
- dex_files.push_back(java_lang_dex_file_);
- dex_files.push_back(conscrypt_file_);
VectorOutputStream output_stream(tmp_elf.GetFilename(), oat_contents);
- bool success_oat = OatWriter::Create(output_stream, dex_files, 0, 0, "", *compiler_driver_.get());
+ bool success_oat = OatWriter::Create(output_stream, class_linker->GetBootClassPath(),
+ 0, 0, "", *compiler_driver_.get());
ASSERT_TRUE(success_oat);
- // Force all system classes into memory
- for (size_t dex_file_index = 0; dex_file_index < dex_files.size(); ++dex_file_index) {
- const DexFile* dex_file = dex_files[dex_file_index];
- for (size_t class_def_index = 0; class_def_index < dex_file->NumClassDefs(); ++class_def_index) {
- const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
- const char* descriptor = dex_file->GetClassDescriptor(class_def);
- mirror::Class* klass = class_linker_->FindSystemClass(descriptor);
- EXPECT_TRUE(klass != NULL) << descriptor;
- }
- }
bool success_elf = compiler_driver_->WriteElf(GetTestAndroidRoot(),
!kIsTargetBuild,
- dex_files,
+ class_linker->GetBootClassPath(),
oat_contents,
tmp_elf.GetFile());
ASSERT_TRUE(success_elf);
@@ -76,10 +68,9 @@ TEST_F(ImageTest, WriteRead) {
ScratchFile tmp_image;
const uintptr_t requested_image_base = ART_BASE_ADDRESS;
{
- ImageWriter writer(NULL);
+ ImageWriter writer(*compiler_driver_.get());
bool success_image = writer.Write(tmp_image.GetFilename(), requested_image_base,
- tmp_oat->GetPath(), tmp_oat->GetPath(),
- *compiler_driver_.get());
+ tmp_oat->GetPath(), tmp_oat->GetPath());
ASSERT_TRUE(success_image);
bool success_fixup = compiler_driver_->FixupElf(tmp_oat.get(), writer.GetOatDataBegin());
ASSERT_TRUE(success_fixup);
@@ -92,15 +83,18 @@ TEST_F(ImageTest, WriteRead) {
file->ReadFully(&image_header, sizeof(image_header));
ASSERT_TRUE(image_header.IsValid());
- Heap* heap = Runtime::Current()->GetHeap();
- ASSERT_EQ(1U, heap->GetSpaces().size());
- ContinuousSpace* space = heap->GetSpaces().front();
+ gc::Heap* heap = Runtime::Current()->GetHeap();
+ ASSERT_EQ(1U, heap->GetContinuousSpaces().size());
+ gc::space::ContinuousSpace* space = heap->GetContinuousSpaces().front();
ASSERT_FALSE(space->IsImageSpace());
ASSERT_TRUE(space != NULL);
- ASSERT_TRUE(space->IsAllocSpace());
+ ASSERT_TRUE(space->IsDlMallocSpace());
ASSERT_GE(sizeof(image_header) + space->Size(), static_cast<size_t>(file->GetLength()));
}
+ ASSERT_TRUE(compiler_driver_->GetImageClasses() != NULL);
+ CompilerDriver::DescriptorSet image_classes(*compiler_driver_->GetImageClasses());
+
// Need to delete the compiler since it has worker threads which are attached to runtime.
compiler_driver_.reset();
@@ -131,14 +125,14 @@ TEST_F(ImageTest, WriteRead) {
ASSERT_TRUE(runtime_.get() != NULL);
class_linker_ = runtime_->GetClassLinker();
- Heap* heap = Runtime::Current()->GetHeap();
- ASSERT_EQ(2U, heap->GetSpaces().size());
- ASSERT_TRUE(heap->GetSpaces()[0]->IsImageSpace());
- ASSERT_FALSE(heap->GetSpaces()[0]->IsAllocSpace());
- ASSERT_FALSE(heap->GetSpaces()[1]->IsImageSpace());
- ASSERT_TRUE(heap->GetSpaces()[1]->IsAllocSpace());
+ gc::Heap* heap = Runtime::Current()->GetHeap();
+ ASSERT_EQ(2U, heap->GetContinuousSpaces().size());
+ ASSERT_TRUE(heap->GetContinuousSpaces()[0]->IsImageSpace());
+ ASSERT_FALSE(heap->GetContinuousSpaces()[0]->IsDlMallocSpace());
+ ASSERT_FALSE(heap->GetContinuousSpaces()[1]->IsImageSpace());
+ ASSERT_TRUE(heap->GetContinuousSpaces()[1]->IsDlMallocSpace());
- ImageSpace* image_space = heap->GetImageSpace();
+ gc::space::ImageSpace* image_space = heap->GetImageSpace();
byte* image_begin = image_space->Begin();
byte* image_end = image_space->End();
CHECK_EQ(requested_image_base, reinterpret_cast<uintptr_t>(image_begin));
@@ -148,7 +142,13 @@ TEST_F(ImageTest, WriteRead) {
mirror::Class* klass = class_linker_->FindSystemClass(descriptor);
EXPECT_TRUE(klass != NULL) << descriptor;
EXPECT_LT(image_begin, reinterpret_cast<byte*>(klass)) << descriptor;
- EXPECT_LT(reinterpret_cast<byte*>(klass), image_end) << descriptor;
+ if (image_classes.find(descriptor) != image_classes.end()) {
+ // image classes should be located before the end of the image.
+ EXPECT_LT(reinterpret_cast<byte*>(klass), image_end) << descriptor;
+ } else {
+ // non image classes should be in a space after the image.
+ EXPECT_GT(reinterpret_cast<byte*>(klass), image_end) << descriptor;
+ }
EXPECT_EQ(*klass->GetRawLockWordAddress(), 0); // address should have been removed from monitor
}
}
diff --git a/src/image_writer.cc b/src/image_writer.cc
index a989a4e0a3..f0b49be8a2 100644
--- a/src/image_writer.cc
+++ b/src/image_writer.cc
@@ -26,17 +26,18 @@
#include "compiled_method.h"
#include "compiler/driver/compiler_driver.h"
#include "dex_file-inl.h"
-#include "gc/card_table-inl.h"
-#include "gc/large_object_space.h"
-#include "gc/space.h"
+#include "gc/accounting/card_table-inl.h"
+#include "gc/accounting/heap_bitmap.h"
+#include "gc/heap.h"
+#include "gc/space/large_object_space.h"
+#include "gc/space/space-inl.h"
#include "globals.h"
-#include "heap.h"
#include "image.h"
#include "intern_table.h"
#include "mirror/array-inl.h"
#include "mirror/class-inl.h"
#include "mirror/class_loader.h"
-#include "mirror/dex_cache.h"
+#include "mirror/dex_cache-inl.h"
#include "mirror/field-inl.h"
#include "mirror/abstract_method-inl.h"
#include "mirror/object-inl.h"
@@ -57,16 +58,12 @@ namespace art {
bool ImageWriter::Write(const std::string& image_filename,
uintptr_t image_begin,
const std::string& oat_filename,
- const std::string& oat_location,
- const CompilerDriver& compiler_driver) {
+ const std::string& oat_location) {
CHECK(!image_filename.empty());
CHECK_NE(image_begin, 0U);
image_begin_ = reinterpret_cast<byte*>(image_begin);
- Heap* heap = Runtime::Current()->GetHeap();
- const Spaces& spaces = heap->GetSpaces();
-
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
const std::vector<DexCache*>& all_dex_caches = class_linker->GetDexCaches();
for (size_t i = 0; i < all_dex_caches.size(); i++) {
@@ -81,6 +78,10 @@ bool ImageWriter::Write(const std::string& image_filename,
}
oat_file_ = OatFile::OpenWritable(oat_file.get(), oat_location);
class_linker->RegisterOatFile(*oat_file_);
+ interpreter_to_interpreter_entry_offset_ = oat_file_->GetOatHeader().GetInterpreterToInterpreterEntryOffset();
+ interpreter_to_quick_entry_offset_ = oat_file_->GetOatHeader().GetInterpreterToQuickEntryOffset();
+ portable_resolution_trampoline_offset_ = oat_file_->GetOatHeader().GetPortableResolutionTrampolineOffset();
+ quick_resolution_trampoline_offset_ = oat_file_->GetOatHeader().GetQuickResolutionTrampolineOffset();
{
Thread::Current()->TransitionFromSuspendedToRunnable();
@@ -89,12 +90,16 @@ bool ImageWriter::Write(const std::string& image_filename,
ComputeEagerResolvedStrings();
Thread::Current()->TransitionFromRunnableToSuspended(kNative);
}
- heap->CollectGarbage(false); // Remove garbage
- // Trim size of alloc spaces
+ gc::Heap* heap = Runtime::Current()->GetHeap();
+ heap->CollectGarbage(false); // Remove garbage.
+ // Trim size of alloc spaces.
+ const std::vector<gc::space::ContinuousSpace*>& spaces = heap->GetContinuousSpaces();
// TODO: C++0x auto
- for (Spaces::const_iterator cur = spaces.begin(); cur != spaces.end(); ++cur) {
- if ((*cur)->IsAllocSpace()) {
- (*cur)->AsAllocSpace()->Trim();
+ typedef std::vector<gc::space::ContinuousSpace*>::const_iterator It;
+ for (It it = spaces.begin(), end = spaces.end(); it != end; ++it) {
+ gc::space::ContinuousSpace* space = *it;
+ if (space->IsDlMallocSpace()) {
+ space->AsDlMallocSpace()->Trim();
}
}
@@ -110,10 +115,10 @@ bool ImageWriter::Write(const std::string& image_filename,
Thread::Current()->TransitionFromSuspendedToRunnable();
size_t oat_loaded_size = 0;
size_t oat_data_offset = 0;
- compiler_driver.GetOatElfInformation(oat_file.get(), oat_loaded_size, oat_data_offset);
+ compiler_driver_.GetOatElfInformation(oat_file.get(), oat_loaded_size, oat_data_offset);
CalculateNewObjectOffsets(oat_loaded_size, oat_data_offset);
CopyAndFixupObjects();
- PatchOatCodeAndMethods(compiler_driver);
+ PatchOatCodeAndMethods();
Thread::Current()->TransitionFromRunnableToSuspended(kNative);
UniquePtr<File> image_file(OS::OpenFile(image_filename.c_str(), true));
@@ -134,11 +139,15 @@ bool ImageWriter::Write(const std::string& image_filename,
}
bool ImageWriter::AllocMemory() {
- const Spaces& spaces = Runtime::Current()->GetHeap()->GetSpaces();
+ gc::Heap* heap = Runtime::Current()->GetHeap();
+ const std::vector<gc::space::ContinuousSpace*>& spaces = heap->GetContinuousSpaces();
size_t size = 0;
- for (Spaces::const_iterator it = spaces.begin(); it != spaces.end(); ++it) {
- if ((*it)->IsAllocSpace()) {
- size += (*it)->Size();
+ // TODO: C++0x auto
+ typedef std::vector<gc::space::ContinuousSpace*>::const_iterator It;
+ for (It it = spaces.begin(), end = spaces.end(); it != end; ++it) {
+ gc::space::ContinuousSpace* space = *it;
+ if (space->IsDlMallocSpace()) {
+ size += space->Size();
}
}
@@ -168,13 +177,13 @@ void ImageWriter::ComputeEagerResolvedStringsCallback(Object* obj, void* arg) {
return;
}
String* string = obj->AsString();
- std::string utf8_string(string->ToModifiedUtf8());
+ const uint16_t* utf16_string = string->GetCharArray()->GetData() + string->GetOffset();
ImageWriter* writer = reinterpret_cast<ImageWriter*>(arg);
typedef Set::const_iterator CacheIt; // TODO: C++0x auto
for (CacheIt it = writer->dex_caches_.begin(), end = writer->dex_caches_.end(); it != end; ++it) {
DexCache* dex_cache = *it;
const DexFile& dex_file = *dex_cache->GetDexFile();
- const DexFile::StringId* string_id = dex_file.FindStringId(utf8_string);
+ const DexFile::StringId* string_id = dex_file.FindStringId(utf16_string);
if (string_id != NULL) {
// This string occurs in this dex file, assign the dex cache entry.
uint32_t string_idx = dex_file.GetIndexForStringId(*string_id);
@@ -188,49 +197,28 @@ void ImageWriter::ComputeEagerResolvedStringsCallback(Object* obj, void* arg) {
void ImageWriter::ComputeEagerResolvedStrings()
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
// TODO: Check image spaces only?
- Heap* heap = Runtime::Current()->GetHeap();
+ gc::Heap* heap = Runtime::Current()->GetHeap();
WriterMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_);
heap->FlushAllocStack();
heap->GetLiveBitmap()->Walk(ComputeEagerResolvedStringsCallback, this);
}
bool ImageWriter::IsImageClass(const Class* klass) {
- if (image_classes_ == NULL) {
- return true;
- }
- while (klass->IsArrayClass()) {
- klass = klass->GetComponentType();
- }
- if (klass->IsPrimitive()) {
- return true;
- }
- const std::string descriptor(ClassHelper(klass).GetDescriptor());
- return image_classes_->find(descriptor) != image_classes_->end();
+ return compiler_driver_.IsImageClass(ClassHelper(klass).GetDescriptor());
}
-
struct NonImageClasses {
ImageWriter* image_writer;
std::set<std::string>* non_image_classes;
};
void ImageWriter::PruneNonImageClasses() {
- if (image_classes_ == NULL) {
+ if (compiler_driver_.GetImageClasses() == NULL) {
return;
}
Runtime* runtime = Runtime::Current();
ClassLinker* class_linker = runtime->GetClassLinker();
- // Update image_classes_ with classes for objects created by <clinit> methods.
- Thread* self = Thread::Current();
- const char* old_cause = self->StartAssertNoThreadSuspension("ImageWriter");
- Heap* heap = Runtime::Current()->GetHeap();
- // TODO: Image spaces only?
- WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
- heap->FlushAllocStack();
- heap->GetLiveBitmap()->Walk(FindClinitImageClassesCallback, this);
- self->EndAssertNoThreadSuspension(old_cause);
-
// Make a list of classes we would like to prune.
std::set<std::string> non_image_classes;
NonImageClasses context;
@@ -271,28 +259,6 @@ void ImageWriter::PruneNonImageClasses() {
}
}
-void ImageWriter::FindClinitImageClassesCallback(Object* object, void* arg) {
- DCHECK(object != NULL);
- DCHECK(arg != NULL);
- ImageWriter* image_writer = reinterpret_cast<ImageWriter*>(arg);
- Class* klass = object->GetClass();
- while (klass->IsArrayClass()) {
- klass = klass->GetComponentType();
- }
- if (klass->IsPrimitive()) {
- return;
- }
- while (!klass->IsObjectClass()) {
- ClassHelper kh(klass);
- const char* descriptor = kh.GetDescriptor();
- std::pair<DescriptorSet::iterator, bool> result = image_writer->image_classes_->insert(descriptor);
- if (result.second) {
- LOG(INFO) << "Adding " << descriptor << " to image classes";
- }
- klass = klass->GetSuperClass();
- }
-}
-
bool ImageWriter::NonImageClassesVisitor(Class* klass, void* arg) {
NonImageClasses* context = reinterpret_cast<NonImageClasses*>(arg);
if (!context->image_writer->IsImageClass(klass)) {
@@ -303,11 +269,11 @@ bool ImageWriter::NonImageClassesVisitor(Class* klass, void* arg) {
void ImageWriter::CheckNonImageClassesRemoved()
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- if (image_classes_ == NULL) {
+ if (compiler_driver_.GetImageClasses() == NULL) {
return;
}
- Heap* heap = Runtime::Current()->GetHeap();
+ gc::Heap* heap = Runtime::Current()->GetHeap();
Thread* self = Thread::Current();
{
WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
@@ -332,8 +298,10 @@ void ImageWriter::CheckNonImageClassesRemovedCallback(Object* obj, void* arg) {
}
void ImageWriter::DumpImageClasses() {
+ CompilerDriver::DescriptorSet* image_classes = compiler_driver_.GetImageClasses();
+ CHECK(image_classes != NULL);
typedef std::set<std::string>::const_iterator It; // TODO: C++0x auto
- for (It it = image_classes_->begin(), end = image_classes_->end(); it != end; ++it) {
+ for (It it = image_classes->begin(), end = image_classes->end(); it != end; ++it) {
LOG(INFO) << " " << *it;
}
}
@@ -410,8 +378,8 @@ void ImageWriter::CalculateNewObjectOffsets(size_t oat_loaded_size, size_t oat_d
Thread* self = Thread::Current();
SirtRef<ObjectArray<Object> > image_roots(self, CreateImageRoots());
- Heap* heap = Runtime::Current()->GetHeap();
- const Spaces& spaces = heap->GetSpaces();
+ gc::Heap* heap = Runtime::Current()->GetHeap();
+ const std::vector<gc::space::ContinuousSpace*>& spaces = heap->GetContinuousSpaces();
DCHECK(!spaces.empty());
DCHECK_EQ(0U, image_end_);
@@ -426,8 +394,11 @@ void ImageWriter::CalculateNewObjectOffsets(size_t oat_loaded_size, size_t oat_d
// TODO: Add InOrderWalk to heap bitmap.
const char* old = self->StartAssertNoThreadSuspension("ImageWriter");
DCHECK(heap->GetLargeObjectsSpace()->GetLiveObjects()->IsEmpty());
- for (Spaces::const_iterator it = spaces.begin(); it != spaces.end(); ++it) {
- (*it)->GetLiveBitmap()->InOrderWalk(CalculateNewObjectOffsetsCallback, this);
+ // TODO: C++0x auto
+ typedef std::vector<gc::space::ContinuousSpace*>::const_iterator It;
+ for (It it = spaces.begin(), end = spaces.end(); it != end; ++it) {
+ gc::space::ContinuousSpace* space = *it;
+ space->GetLiveBitmap()->InOrderWalk(CalculateNewObjectOffsetsCallback, this);
DCHECK_LT(image_end_, image_->Size());
}
self->EndAssertNoThreadSuspension(old);
@@ -455,7 +426,7 @@ void ImageWriter::CopyAndFixupObjects()
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
Thread* self = Thread::Current();
const char* old_cause = self->StartAssertNoThreadSuspension("ImageWriter");
- Heap* heap = Runtime::Current()->GetHeap();
+ gc::Heap* heap = Runtime::Current()->GetHeap();
// TODO: heap validation can't handle this fix up pass
heap->DisableObjectValidation();
// TODO: Image spaces only?
@@ -512,17 +483,34 @@ void ImageWriter::FixupMethod(const AbstractMethod* orig, AbstractMethod* copy)
if (orig->IsAbstract()) {
// Code for abstract methods is set to the abstract method error stub when we load the image.
copy->SetEntryPointFromCompiledCode(NULL);
+ copy->SetEntryPointFromInterpreter(reinterpret_cast<EntryPointFromInterpreter*>
+ (GetOatAddress(interpreter_to_interpreter_entry_offset_)));
return;
+ } else {
+ copy->SetEntryPointFromInterpreter(reinterpret_cast<EntryPointFromInterpreter*>
+ (GetOatAddress(interpreter_to_quick_entry_offset_)));
}
if (orig == Runtime::Current()->GetResolutionMethod()) {
- // The resolution method's code is set to the resolution trampoline when we load the image.
- copy->SetEntryPointFromCompiledCode(NULL);
+#if defined(ART_USE_PORTABLE_COMPILER)
+ copy->SetEntryPointFromCompiledCode(GetOatAddress(portable_resolution_trampoline_offset_));
+#else
+ copy->SetEntryPointFromCompiledCode(GetOatAddress(quick_resolution_trampoline_offset_));
+#endif
return;
}
- // Non-abstract methods have code
- copy->SetEntryPointFromCompiledCode(GetOatAddress(orig->GetOatCodeOffset()));
+ // Use original code if it exists. Otherwise, set the code pointer to the resolution trampoline.
+ const byte* code = GetOatAddress(orig->GetOatCodeOffset());
+ if (code != NULL) {
+ copy->SetEntryPointFromCompiledCode(code);
+ } else {
+#if defined(ART_USE_PORTABLE_COMPILER)
+ copy->SetEntryPointFromCompiledCode(GetOatAddress(portable_resolution_trampoline_offset_));
+#else
+ copy->SetEntryPointFromCompiledCode(GetOatAddress(quick_resolution_trampoline_offset_));
+#endif
+ }
if (orig->IsNative()) {
// The native method's pointer is set to a stub to lookup via dlsym when we load the image.
@@ -638,13 +626,13 @@ static AbstractMethod* GetTargetMethod(const CompilerDriver::PatchInformation* p
return method;
}
-void ImageWriter::PatchOatCodeAndMethods(const CompilerDriver& compiler) {
+void ImageWriter::PatchOatCodeAndMethods() {
Thread* self = Thread::Current();
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
const char* old_cause = self->StartAssertNoThreadSuspension("ImageWriter");
typedef std::vector<const CompilerDriver::PatchInformation*> Patches;
- const Patches& code_to_patch = compiler.GetCodeToPatch();
+ const Patches& code_to_patch = compiler_driver_.GetCodeToPatch();
for (size_t i = 0; i < code_to_patch.size(); i++) {
const CompilerDriver::PatchInformation* patch = code_to_patch[i];
AbstractMethod* target = GetTargetMethod(patch);
@@ -654,7 +642,7 @@ void ImageWriter::PatchOatCodeAndMethods(const CompilerDriver& compiler) {
SetPatchLocation(patch, reinterpret_cast<uint32_t>(GetOatAddress(code_offset)));
}
- const Patches& methods_to_patch = compiler.GetMethodsToPatch();
+ const Patches& methods_to_patch = compiler_driver_.GetMethodsToPatch();
for (size_t i = 0; i < methods_to_patch.size(); i++) {
const CompilerDriver::PatchInformation* patch = methods_to_patch[i];
AbstractMethod* target = GetTargetMethod(patch);
diff --git a/src/image_writer.h b/src/image_writer.h
index 30a7f7f5da..b79cb2f0c2 100644
--- a/src/image_writer.h
+++ b/src/image_writer.h
@@ -29,7 +29,7 @@
#include "mirror/dex_cache.h"
#include "os.h"
#include "safe_map.h"
-#include "gc/space.h"
+#include "gc/space/space.h"
#include "UniquePtr.h"
namespace art {
@@ -37,18 +37,18 @@ namespace art {
// Write a Space built during compilation for use during execution.
class ImageWriter {
public:
- typedef std::set<std::string> DescriptorSet;
- explicit ImageWriter(DescriptorSet* image_classes)
- : oat_file_(NULL), image_end_(0), image_begin_(NULL), image_classes_(image_classes),
- oat_data_begin_(NULL) {}
+ explicit ImageWriter(const CompilerDriver& compiler_driver)
+ : compiler_driver_(compiler_driver), oat_file_(NULL), image_end_(0), image_begin_(NULL),
+ oat_data_begin_(NULL), interpreter_to_interpreter_entry_offset_(0),
+ interpreter_to_quick_entry_offset_(0), portable_resolution_trampoline_offset_(0),
+ quick_resolution_trampoline_offset_(0) {}
~ImageWriter() {}
bool Write(const std::string& image_filename,
uintptr_t image_begin,
const std::string& oat_filename,
- const std::string& oat_location,
- const CompilerDriver& compiler_driver)
+ const std::string& oat_location)
LOCKS_EXCLUDED(Locks::mutator_lock_);
uintptr_t GetOatDataBegin() {
@@ -130,8 +130,6 @@ class ImageWriter {
// Remove unwanted classes from various roots.
void PruneNonImageClasses() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- static void FindClinitImageClassesCallback(mirror::Object* object, void* arg)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
static bool NonImageClassesVisitor(mirror::Class* c, void* arg)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -170,12 +168,14 @@ class ImageWriter {
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Patches references in OatFile to expect runtime addresses.
- void PatchOatCodeAndMethods(const CompilerDriver& compiler)
+ void PatchOatCodeAndMethods()
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
void SetPatchLocation(const CompilerDriver::PatchInformation* patch, uint32_t value)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ const CompilerDriver& compiler_driver_;
+
// Map of Object to where it will be at runtime.
SafeMap<const mirror::Object*, size_t> offsets_;
@@ -191,13 +191,16 @@ class ImageWriter {
// Beginning target image address for the output image.
byte* image_begin_;
- // Set of classes to be include in the image, or NULL for all.
- DescriptorSet* image_classes_;
-
// Beginning target oat address for the pointers from the output image to its oat file.
const byte* oat_data_begin_;
- // DexCaches seen while scanning for fixing up CodeAndDirectMethods.
+ // Offset from oat_data_begin_ to the stubs.
+ uint32_t interpreter_to_interpreter_entry_offset_;
+ uint32_t interpreter_to_quick_entry_offset_;
+ uint32_t portable_resolution_trampoline_offset_;
+ uint32_t quick_resolution_trampoline_offset_;
+
+ // DexCaches seen while scanning for fixing up CodeAndDirectMethods
typedef std::set<mirror::DexCache*> Set;
Set dex_caches_;
};
diff --git a/src/instrumentation.cc b/src/instrumentation.cc
index 39fd37766a..8af0885ef4 100644
--- a/src/instrumentation.cc
+++ b/src/instrumentation.cc
@@ -62,7 +62,7 @@ bool Instrumentation::InstallStubsForClass(mirror::Class* klass) {
if (is_initialized || !method->IsStatic() || method->IsConstructor()) {
new_code = class_linker->GetOatCodeFor(method);
} else {
- new_code = GetResolutionTrampoline();
+ new_code = GetResolutionTrampoline(class_linker);
}
} else { // !uninstall
if (!interpreter_stubs_installed_ || method->IsNative()) {
@@ -380,7 +380,7 @@ const void* Instrumentation::GetQuickCodeFor(const mirror::AbstractMethod* metho
if (LIKELY(!instrumentation_stubs_installed_)) {
const void* code = method->GetEntryPointFromCompiledCode();
DCHECK(code != NULL);
- if (LIKELY(code != GetResolutionTrampoline())) {
+ if (LIKELY(code != GetResolutionTrampoline(runtime->GetClassLinker()))) {
return code;
}
}
diff --git a/src/instrumentation.h b/src/instrumentation.h
index e6fa251076..e79c75efac 100644
--- a/src/instrumentation.h
+++ b/src/instrumentation.h
@@ -137,12 +137,24 @@ class Instrumentation {
return instrumentation_stubs_installed_;
}
+ bool HasMethodEntryListeners() const {
+ return have_method_entry_listeners_;
+ }
+
+ bool HasMethodExitListeners() const {
+ return have_method_exit_listeners_;
+ }
+
+ bool HasDexPcListeners() const {
+ return have_dex_pc_listeners_;
+ }
+
// Inform listeners that a method has been entered. A dex PC is provided as we may install
// listeners into executing code and get method enter events for methods already on the stack.
void MethodEnterEvent(Thread* thread, mirror::Object* this_object,
const mirror::AbstractMethod* method, uint32_t dex_pc) const
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- if (have_method_entry_listeners_) {
+ if (UNLIKELY(HasMethodEntryListeners())) {
MethodEnterEventImpl(thread, this_object, method, dex_pc);
}
}
@@ -152,7 +164,7 @@ class Instrumentation {
const mirror::AbstractMethod* method, uint32_t dex_pc,
const JValue& return_value) const
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- if (have_method_exit_listeners_) {
+ if (UNLIKELY(HasMethodExitListeners())) {
MethodExitEventImpl(thread, this_object, method, dex_pc, return_value);
}
}
@@ -166,7 +178,7 @@ class Instrumentation {
void DexPcMovedEvent(Thread* thread, mirror::Object* this_object,
const mirror::AbstractMethod* method, uint32_t dex_pc) const
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- if (UNLIKELY(have_dex_pc_listeners_)) {
+ if (UNLIKELY(HasDexPcListeners())) {
DexPcMovedEventImpl(thread, this_object, method, dex_pc);
}
}
diff --git a/src/intern_table.cc b/src/intern_table.cc
index fa3c0753a9..d1ad2dbadc 100644
--- a/src/intern_table.cc
+++ b/src/intern_table.cc
@@ -38,13 +38,15 @@ void InternTable::DumpForSigQuit(std::ostream& os) const {
<< image_strong_interns_.size() << " image strong\n";
}
-void InternTable::VisitRoots(RootVisitor* visitor, void* arg) {
+void InternTable::VisitRoots(RootVisitor* visitor, void* arg, bool clean_dirty) {
MutexLock mu(Thread::Current(), intern_table_lock_);
typedef Table::const_iterator It; // TODO: C++0x auto
for (It it = strong_interns_.begin(), end = strong_interns_.end(); it != end; ++it) {
visitor(it->second, arg);
}
- is_dirty_ = false;
+ if (clean_dirty) {
+ is_dirty_ = false;
+ }
// Note: we deliberately don't visit the weak_interns_ table and the immutable image roots.
}
diff --git a/src/intern_table.h b/src/intern_table.h
index 3018317e0f..1ff4f6d3c6 100644
--- a/src/intern_table.h
+++ b/src/intern_table.h
@@ -66,7 +66,7 @@ class InternTable {
size_t Size() const;
- void VisitRoots(RootVisitor* visitor, void* arg);
+ void VisitRoots(RootVisitor* visitor, void* arg, bool clean_dirty);
void DumpForSigQuit(std::ostream& os) const;
diff --git a/src/interpreter/interpreter.cc b/src/interpreter/interpreter.cc
index e2cc3d63aa..1e8ee9c63c 100644
--- a/src/interpreter/interpreter.cc
+++ b/src/interpreter/interpreter.cc
@@ -23,7 +23,8 @@
#include "common_throws.h"
#include "dex_file-inl.h"
#include "dex_instruction-inl.h"
-#include "gc/card_table-inl.h"
+#include "dex_instruction.h"
+#include "gc/accounting/card_table-inl.h"
#include "invoke_arg_array_builder.h"
#include "nth_caller_visitor.h"
#include "mirror/class.h"
@@ -50,12 +51,13 @@ static const int32_t kMinInt = std::numeric_limits<int32_t>::min();
static const int64_t kMaxLong = std::numeric_limits<int64_t>::max();
static const int64_t kMinLong = std::numeric_limits<int64_t>::min();
-static void UnstartedRuntimeInvoke(Thread* self, AbstractMethod* target_method,
- ShadowFrame* shadow_frame, JValue* result, size_t arg_offset)
+static void UnstartedRuntimeInvoke(Thread* self, MethodHelper& mh,
+ const DexFile::CodeItem* code_item, ShadowFrame* shadow_frame,
+ JValue* result, size_t arg_offset)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
// In a runtime that's not started we intercept certain methods to avoid complicated dependency
// problems in core libraries.
- std::string name(PrettyMethod(target_method));
+ std::string name(PrettyMethod(shadow_frame->GetMethod()));
if (name == "java.lang.Class java.lang.Class.forName(java.lang.String)") {
std::string descriptor(DotToDescriptor(shadow_frame->GetVRegReference(arg_offset)->AsString()->ToModifiedUtf8().c_str()));
ClassLoader* class_loader = NULL; // shadow_frame.GetMethod()->GetDeclaringClass()->GetClassLoader();
@@ -132,7 +134,7 @@ static void UnstartedRuntimeInvoke(Thread* self, AbstractMethod* target_method,
}
} else {
// Not special, continue with regular interpreter execution.
- EnterInterpreterFromInterpreter(self, shadow_frame, result);
+ artInterpreterToInterpreterEntry(self, mh, code_item, shadow_frame, result);
}
}
@@ -383,43 +385,133 @@ static void DoMonitorExit(Thread* self, Object* ref) NO_THREAD_SAFETY_ANALYSIS {
ref->MonitorExit(self);
}
-static void DoInvoke(Thread* self, MethodHelper& mh, ShadowFrame& shadow_frame,
- const Instruction* inst, InvokeType type, bool is_range,
- JValue* result)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+// TODO: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) which is failing due to template
+// specialization.
+template<InvokeType type, bool is_range, bool do_access_check>
+static void DoInvoke(Thread* self, ShadowFrame& shadow_frame,
+ const Instruction* inst, JValue* result) NO_THREAD_SAFETY_ANALYSIS;
+
+template<InvokeType type, bool is_range, bool do_access_check>
+static void DoInvoke(Thread* self, ShadowFrame& shadow_frame,
+ const Instruction* inst, JValue* result) {
+ uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
uint32_t vregC = (is_range) ? inst->VRegC_3rc() : inst->VRegC_35c();
- Object* receiver;
- if (type == kStatic) {
- receiver = NULL;
+ Object* receiver = (type == kStatic) ? NULL : shadow_frame.GetVRegReference(vregC);
+ AbstractMethod* method = FindMethodFromCode(method_idx, receiver, shadow_frame.GetMethod(), self,
+ do_access_check, type);
+ if (UNLIKELY(method == NULL)) {
+ CHECK(self->IsExceptionPending());
+ result->SetJ(0);
+ return;
+ }
+
+ MethodHelper mh(method);
+ const DexFile::CodeItem* code_item = mh.GetCodeItem();
+ uint16_t num_regs;
+ uint16_t num_ins;
+ if (LIKELY(code_item != NULL)) {
+ num_regs = code_item->registers_size_;
+ num_ins = code_item->ins_size_;
+ } else if (method->IsAbstract()) {
+ ThrowLocation throw_location = self->GetCurrentLocationForThrow();
+ self->ThrowNewExceptionF(throw_location, "Ljava/lang/AbstractMethodError;",
+ "abstract method \"%s\"", PrettyMethod(method).c_str());
+ return;
} else {
- receiver = shadow_frame.GetVRegReference(vregC);
+ DCHECK(method->IsNative() || method->IsProxyMethod());
+ num_regs = num_ins = AbstractMethod::NumArgRegisters(mh.GetShorty());
+ if (!method->IsStatic()) {
+ num_regs++;
+ num_ins++;
+ }
}
- uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
- AbstractMethod* target_method = FindMethodFromCode(method_idx, receiver,
- shadow_frame.GetMethod(),
- self, true, type);
- if (UNLIKELY(target_method == NULL)) {
+
+ void* memory = alloca(ShadowFrame::ComputeSize(num_regs));
+ ShadowFrame* new_shadow_frame(ShadowFrame::Create(num_regs, &shadow_frame, method, 0, memory));
+ size_t cur_reg = num_regs - num_ins;
+ if (receiver != NULL) {
+ new_shadow_frame->SetVRegReference(cur_reg, receiver);
+ ++cur_reg;
+ }
+
+ size_t arg_offset = (receiver == NULL) ? 0 : 1;
+ const char* shorty = mh.GetShorty();
+ uint32_t arg[5];
+ if (!is_range) {
+ inst->GetArgs(arg);
+ }
+ for (size_t shorty_pos = 0; cur_reg < num_regs; ++shorty_pos, cur_reg++, arg_offset++) {
+ DCHECK_LT(shorty_pos + 1, mh.GetShortyLength());
+ size_t arg_pos = is_range ? vregC + arg_offset : arg[arg_offset];
+ switch (shorty[shorty_pos + 1]) {
+ case 'L': {
+ Object* o = shadow_frame.GetVRegReference(arg_pos);
+ new_shadow_frame->SetVRegReference(cur_reg, o);
+ break;
+ }
+ case 'J': case 'D': {
+ uint64_t wide_value = (static_cast<uint64_t>(shadow_frame.GetVReg(arg_pos + 1)) << 32) |
+ static_cast<uint32_t>(shadow_frame.GetVReg(arg_pos));
+ new_shadow_frame->SetVRegLong(cur_reg, wide_value);
+ cur_reg++;
+ arg_offset++;
+ break;
+ }
+ default:
+ new_shadow_frame->SetVReg(cur_reg, shadow_frame.GetVReg(arg_pos));
+ break;
+ }
+ }
+
+ if (LIKELY(Runtime::Current()->IsStarted())) {
+ (method->GetEntryPointFromInterpreter())(self, mh, code_item, new_shadow_frame, result);
+ } else {
+ UnstartedRuntimeInvoke(self, mh, code_item, new_shadow_frame, result, num_regs - num_ins);
+ }
+}
+
+// TODO: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) which is failing due to template
+// specialization.
+template<bool is_range>
+static void DoInvokeVirtualQuick(Thread* self, ShadowFrame& shadow_frame,
+ const Instruction* inst, JValue* result)
+ NO_THREAD_SAFETY_ANALYSIS;
+
+template<bool is_range>
+static void DoInvokeVirtualQuick(Thread* self, ShadowFrame& shadow_frame,
+ const Instruction* inst, JValue* result) {
+ uint32_t vregC = (is_range) ? inst->VRegC_3rc() : inst->VRegC_35c();
+ Object* receiver = shadow_frame.GetVRegReference(vregC);
+ if (UNLIKELY(receiver == NULL)) {
+ // We lost the reference to the method index so we cannot get a more
+ // precised exception message.
+ ThrowNullPointerExceptionFromDexPC(shadow_frame.GetCurrentLocationForThrow());
+ return;
+ }
+ uint32_t vtable_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
+ AbstractMethod* method = receiver->GetClass()->GetVTable()->Get(vtable_idx);
+ if (UNLIKELY(method == NULL)) {
CHECK(self->IsExceptionPending());
result->SetJ(0);
return;
}
- MethodHelper target_mh(target_method);
+ MethodHelper mh(method);
- const DexFile::CodeItem* code_item = target_mh.GetCodeItem();
+ const DexFile::CodeItem* code_item = mh.GetCodeItem();
uint16_t num_regs;
uint16_t num_ins;
if (code_item != NULL) {
num_regs = code_item->registers_size_;
num_ins = code_item->ins_size_;
- } else if (target_method->IsAbstract()) {
+ } else if (method->IsAbstract()) {
ThrowLocation throw_location = self->GetCurrentLocationForThrow();
self->ThrowNewExceptionF(throw_location, "Ljava/lang/AbstractMethodError;",
- "abstract method \"%s\"", PrettyMethod(target_method).c_str());
+ "abstract method \"%s\"", PrettyMethod(method).c_str());
return;
} else {
- DCHECK(target_method->IsNative() || target_method->IsProxyMethod());
- num_regs = num_ins = AbstractMethod::NumArgRegisters(target_mh.GetShorty());
- if (!target_method->IsStatic()) {
+ DCHECK(method->IsNative() || method->IsProxyMethod());
+ num_regs = num_ins = AbstractMethod::NumArgRegisters(mh.GetShorty());
+ if (!method->IsStatic()) {
num_regs++;
num_ins++;
}
@@ -427,7 +519,7 @@ static void DoInvoke(Thread* self, MethodHelper& mh, ShadowFrame& shadow_frame,
void* memory = alloca(ShadowFrame::ComputeSize(num_regs));
ShadowFrame* new_shadow_frame(ShadowFrame::Create(num_regs, &shadow_frame,
- target_method, 0, memory));
+ method, 0, memory));
size_t cur_reg = num_regs - num_ins;
if (receiver != NULL) {
new_shadow_frame->SetVRegReference(cur_reg, receiver);
@@ -435,13 +527,13 @@ static void DoInvoke(Thread* self, MethodHelper& mh, ShadowFrame& shadow_frame,
}
size_t arg_offset = (receiver == NULL) ? 0 : 1;
- const char* shorty = target_mh.GetShorty();
+ const char* shorty = mh.GetShorty();
uint32_t arg[5];
if (!is_range) {
inst->GetArgs(arg);
}
for (size_t shorty_pos = 0; cur_reg < num_regs; ++shorty_pos, cur_reg++, arg_offset++) {
- DCHECK_LT(shorty_pos + 1, target_mh.GetShortyLength());
+ DCHECK_LT(shorty_pos + 1, mh.GetShortyLength());
size_t arg_pos = is_range ? vregC + arg_offset : arg[arg_offset];
switch (shorty[shorty_pos + 1]) {
case 'L': {
@@ -464,24 +556,33 @@ static void DoInvoke(Thread* self, MethodHelper& mh, ShadowFrame& shadow_frame,
}
if (LIKELY(Runtime::Current()->IsStarted())) {
- (target_method->GetEntryPointFromInterpreter())(self, new_shadow_frame, result);
+ (method->GetEntryPointFromInterpreter())(self, mh, code_item, new_shadow_frame, result);
} else {
- UnstartedRuntimeInvoke(self, target_method, new_shadow_frame, result, num_regs - num_ins);
+ UnstartedRuntimeInvoke(self, mh, code_item, new_shadow_frame, result, num_regs - num_ins);
}
}
+// We use template functions to optimize compiler inlining process. Otherwise,
+// some parts of the code (like a switch statement) which depend on a constant
+// parameter would not be inlined while it should be. These constant parameters
+// are now part of the template arguments.
+// Note these template functions are static and inlined so they should not be
+// part of the final object file.
+// TODO: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) which is failing due to template
+// specialization.
+template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check>
static void DoFieldGet(Thread* self, ShadowFrame& shadow_frame,
- const Instruction* inst, FindFieldType find_type,
- Primitive::Type field_type)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE;
+ const Instruction* inst)
+ NO_THREAD_SAFETY_ANALYSIS ALWAYS_INLINE;
+template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check>
static inline void DoFieldGet(Thread* self, ShadowFrame& shadow_frame,
- const Instruction* inst, FindFieldType find_type,
- Primitive::Type field_type) {
+ const Instruction* inst) {
bool is_static = (find_type == StaticObjectRead) || (find_type == StaticPrimitiveRead);
uint32_t field_idx = is_static ? inst->VRegB_21c() : inst->VRegC_22c();
Field* f = FindFieldFromCode(field_idx, shadow_frame.GetMethod(), self,
- find_type, Primitive::FieldSize(field_type));
+ find_type, Primitive::FieldSize(field_type),
+ do_access_check);
if (UNLIKELY(f == NULL)) {
CHECK(self->IsExceptionPending());
return;
@@ -524,18 +625,56 @@ static inline void DoFieldGet(Thread* self, ShadowFrame& shadow_frame,
}
}
-static void DoFieldPut(Thread* self, ShadowFrame& shadow_frame,
- const Instruction* inst, FindFieldType find_type,
- Primitive::Type field_type)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE;
+// TODO: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) which is failing due to template
+// specialization.
+template<Primitive::Type field_type>
+static void DoIGetQuick(Thread* self, ShadowFrame& shadow_frame,
+ const Instruction* inst)
+ NO_THREAD_SAFETY_ANALYSIS ALWAYS_INLINE;
+
+template<Primitive::Type field_type>
+static inline void DoIGetQuick(Thread* self, ShadowFrame& shadow_frame,
+ const Instruction* inst) {
+ Object* obj = shadow_frame.GetVRegReference(inst->VRegB_22c());
+ if (UNLIKELY(obj == NULL)) {
+ // We lost the reference to the field index so we cannot get a more
+ // precised exception message.
+ ThrowNullPointerExceptionFromDexPC(shadow_frame.GetCurrentLocationForThrow());
+ return;
+ }
+ MemberOffset field_offset(inst->VRegC_22c());
+ const bool is_volatile = false; // iget-x-quick only on non volatile fields.
+ const uint32_t vregA = inst->VRegA_22c();
+ switch (field_type) {
+ case Primitive::kPrimInt:
+ shadow_frame.SetVReg(vregA, static_cast<int32_t>(obj->GetField32(field_offset, is_volatile)));
+ break;
+ case Primitive::kPrimLong:
+ shadow_frame.SetVRegLong(vregA, static_cast<int64_t>(obj->GetField64(field_offset, is_volatile)));
+ break;
+ case Primitive::kPrimNot:
+ shadow_frame.SetVRegReference(vregA, obj->GetFieldObject<mirror::Object*>(field_offset, is_volatile));
+ break;
+ default:
+ LOG(FATAL) << "Unreachable: " << field_type;
+ }
+}
+
+// TODO: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) which is failing due to template
+// specialization.
+template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check>
+static void DoFieldPut(Thread* self, const ShadowFrame& shadow_frame,
+ const Instruction* inst)
+ NO_THREAD_SAFETY_ANALYSIS ALWAYS_INLINE;
-static inline void DoFieldPut(Thread* self, ShadowFrame& shadow_frame,
- const Instruction* inst, FindFieldType find_type,
- Primitive::Type field_type) {
+template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check>
+static inline void DoFieldPut(Thread* self, const ShadowFrame& shadow_frame,
+ const Instruction* inst) {
bool is_static = (find_type == StaticObjectWrite) || (find_type == StaticPrimitiveWrite);
uint32_t field_idx = is_static ? inst->VRegB_21c() : inst->VRegC_22c();
Field* f = FindFieldFromCode(field_idx, shadow_frame.GetMethod(), self,
- find_type, Primitive::FieldSize(field_type));
+ find_type, Primitive::FieldSize(field_type),
+ do_access_check);
if (UNLIKELY(f == NULL)) {
CHECK(self->IsExceptionPending());
return;
@@ -579,6 +718,41 @@ static inline void DoFieldPut(Thread* self, ShadowFrame& shadow_frame,
}
}
+// TODO: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) which is failing due to template
+// specialization.
+template<Primitive::Type field_type>
+static void DoIPutQuick(Thread* self, ShadowFrame& shadow_frame,
+ const Instruction* inst)
+ NO_THREAD_SAFETY_ANALYSIS ALWAYS_INLINE;
+
+template<Primitive::Type field_type>
+static inline void DoIPutQuick(Thread* self, ShadowFrame& shadow_frame,
+ const Instruction* inst) {
+ Object* obj = shadow_frame.GetVRegReference(inst->VRegB_22c());
+ if (UNLIKELY(obj == NULL)) {
+ // We lost the reference to the field index so we cannot get a more
+ // precised exception message.
+ ThrowNullPointerExceptionFromDexPC(shadow_frame.GetCurrentLocationForThrow());
+ return;
+ }
+ MemberOffset field_offset(inst->VRegC_22c());
+ const bool is_volatile = false; // iput-x-quick only on non volatile fields.
+ const uint32_t vregA = inst->VRegA_22c();
+ switch (field_type) {
+ case Primitive::kPrimInt:
+ obj->SetField32(field_offset, shadow_frame.GetVReg(vregA), is_volatile);
+ break;
+ case Primitive::kPrimLong:
+ obj->SetField64(field_offset, shadow_frame.GetVRegLong(vregA), is_volatile);
+ break;
+ case Primitive::kPrimNot:
+ obj->SetFieldObject(field_offset, shadow_frame.GetVRegReference(vregA), is_volatile);
+ break;
+ default:
+ LOG(FATAL) << "Unreachable: " << field_type;
+ }
+}
+
static inline String* ResolveString(Thread* self, MethodHelper& mh, uint32_t string_idx)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
Class* java_lang_string_class = String::GetJavaLangString();
@@ -593,10 +767,11 @@ static inline String* ResolveString(Thread* self, MethodHelper& mh, uint32_t str
return mh.ResolveString(string_idx);
}
-static inline void DoIntDivide(Thread* self, ShadowFrame& shadow_frame, size_t result_reg,
- int32_t dividend, int32_t divisor) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+static inline void DoIntDivide(ShadowFrame& shadow_frame, size_t result_reg,
+ int32_t dividend, int32_t divisor)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
if (UNLIKELY(divisor == 0)) {
- ThrowArithmeticExceptionDivideByZero(self);
+ ThrowArithmeticExceptionDivideByZero();
} else if (UNLIKELY(dividend == kMinInt && divisor == -1)) {
shadow_frame.SetVReg(result_reg, kMinInt);
} else {
@@ -604,10 +779,11 @@ static inline void DoIntDivide(Thread* self, ShadowFrame& shadow_frame, size_t r
}
}
-static inline void DoIntRemainder(Thread* self, ShadowFrame& shadow_frame, size_t result_reg,
- int32_t dividend, int32_t divisor) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+static inline void DoIntRemainder(ShadowFrame& shadow_frame, size_t result_reg,
+ int32_t dividend, int32_t divisor)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
if (UNLIKELY(divisor == 0)) {
- ThrowArithmeticExceptionDivideByZero(self);
+ ThrowArithmeticExceptionDivideByZero();
} else if (UNLIKELY(dividend == kMinInt && divisor == -1)) {
shadow_frame.SetVReg(result_reg, 0);
} else {
@@ -615,10 +791,11 @@ static inline void DoIntRemainder(Thread* self, ShadowFrame& shadow_frame, size_
}
}
-static inline void DoLongDivide(Thread* self, ShadowFrame& shadow_frame, size_t result_reg,
- int64_t dividend, int64_t divisor) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+static inline void DoLongDivide(ShadowFrame& shadow_frame, size_t result_reg,
+ int64_t dividend, int64_t divisor)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
if (UNLIKELY(divisor == 0)) {
- ThrowArithmeticExceptionDivideByZero(self);
+ ThrowArithmeticExceptionDivideByZero();
} else if (UNLIKELY(dividend == kMinLong && divisor == -1)) {
shadow_frame.SetVRegLong(result_reg, kMinLong);
} else {
@@ -626,10 +803,11 @@ static inline void DoLongDivide(Thread* self, ShadowFrame& shadow_frame, size_t
}
}
-static inline void DoLongRemainder(Thread* self, ShadowFrame& shadow_frame, size_t result_reg,
- int64_t dividend, int64_t divisor) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+static inline void DoLongRemainder(ShadowFrame& shadow_frame, size_t result_reg,
+ int64_t dividend, int64_t divisor)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
if (UNLIKELY(divisor == 0)) {
- ThrowArithmeticExceptionDivideByZero(self);
+ ThrowArithmeticExceptionDivideByZero();
} else if (UNLIKELY(dividend == kMinLong && divisor == -1)) {
shadow_frame.SetVRegLong(result_reg, 0);
} else {
@@ -637,6 +815,111 @@ static inline void DoLongRemainder(Thread* self, ShadowFrame& shadow_frame, size
}
}
+// TODO: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) which is failing due to template
+// specialization.
+// Returns true on success, otherwise throws an exception and returns false.
+template <bool is_range, bool do_access_check>
+static bool DoFilledNewArray(const Instruction* inst, const ShadowFrame& shadow_frame,
+ Thread* self, JValue* result)
+ NO_THREAD_SAFETY_ANALYSIS ALWAYS_INLINE;
+
+template <bool is_range, bool do_access_check>
+static inline bool DoFilledNewArray(const Instruction* inst,
+ const ShadowFrame& shadow_frame,
+ Thread* self, JValue* result) {
+ DCHECK(inst->Opcode() == Instruction::FILLED_NEW_ARRAY ||
+ inst->Opcode() == Instruction::FILLED_NEW_ARRAY_RANGE);
+ const int32_t length = is_range ? inst->VRegA_3rc() : inst->VRegA_35c();
+ if (!is_range) {
+ // Checks FILLED_NEW_ARRAY's length does not exceed 5 arguments.
+ CHECK_LE(length, 5);
+ }
+ if (UNLIKELY(length < 0)) {
+ ThrowNegativeArraySizeException(length);
+ return false;
+ }
+ uint16_t type_idx = is_range ? inst->VRegB_3rc() : inst->VRegB_35c();
+ Class* arrayClass = ResolveVerifyAndClinit(type_idx, shadow_frame.GetMethod(),
+ self, false, do_access_check);
+ if (UNLIKELY(arrayClass == NULL)) {
+ DCHECK(self->IsExceptionPending());
+ return false;
+ }
+ CHECK(arrayClass->IsArrayClass());
+ Class* componentClass = arrayClass->GetComponentType();
+ if (UNLIKELY(componentClass->IsPrimitive() && !componentClass->IsPrimitiveInt())) {
+ if (componentClass->IsPrimitiveLong() || componentClass->IsPrimitiveDouble()) {
+ ThrowRuntimeException("Bad filled array request for type %s",
+ PrettyDescriptor(componentClass).c_str());
+ } else {
+ self->ThrowNewExceptionF(shadow_frame.GetCurrentLocationForThrow(),
+ "Ljava/lang/InternalError;",
+ "Found type %s; filled-new-array not implemented for anything but \'int\'",
+ PrettyDescriptor(componentClass).c_str());
+ }
+ return false;
+ }
+ Object* newArray = Array::Alloc(self, arrayClass, length);
+ if (UNLIKELY(newArray == NULL)) {
+ DCHECK(self->IsExceptionPending());
+ return false;
+ }
+ if (is_range) {
+ uint32_t vregC = inst->VRegC_3rc();
+ const bool is_primitive_int_component = componentClass->IsPrimitiveInt();
+ for (int32_t i = 0; i < length; ++i) {
+ if (is_primitive_int_component) {
+ newArray->AsIntArray()->Set(i, shadow_frame.GetVReg(vregC + i));
+ } else {
+ newArray->AsObjectArray<Object>()->Set(i, shadow_frame.GetVRegReference(vregC + i));
+ }
+ }
+ } else {
+ uint32_t arg[5];
+ inst->GetArgs(arg);
+ const bool is_primitive_int_component = componentClass->IsPrimitiveInt();
+ for (int32_t i = 0; i < length; ++i) {
+ if (is_primitive_int_component) {
+ newArray->AsIntArray()->Set(i, shadow_frame.GetVReg(arg[i]));
+ } else {
+ newArray->AsObjectArray<Object>()->Set(i, shadow_frame.GetVRegReference(arg[i]));
+ }
+ }
+ }
+
+ result->SetL(newArray);
+ return true;
+}
+
+static inline const Instruction* DoSparseSwitch(const Instruction* inst,
+ const ShadowFrame& shadow_frame)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ DCHECK(inst->Opcode() == Instruction::SPARSE_SWITCH);
+ const uint16_t* switch_data = reinterpret_cast<const uint16_t*>(inst) + inst->VRegB_31t();
+ int32_t test_val = shadow_frame.GetVReg(inst->VRegA_31t());
+ DCHECK_EQ(switch_data[0], static_cast<uint16_t>(Instruction::kSparseSwitchSignature));
+ uint16_t size = switch_data[1];
+ DCHECK_GT(size, 0);
+ const int32_t* keys = reinterpret_cast<const int32_t*>(&switch_data[2]);
+ DCHECK(IsAligned<4>(keys));
+ const int32_t* entries = keys + size;
+ DCHECK(IsAligned<4>(entries));
+ int lo = 0;
+ int hi = size - 1;
+ while (lo <= hi) {
+ int mid = (lo + hi) / 2;
+ int32_t foundVal = keys[mid];
+ if (test_val < foundVal) {
+ hi = mid - 1;
+ } else if (test_val > foundVal) {
+ lo = mid + 1;
+ } else {
+ return inst->RelativeAt(entries[mid]);
+ }
+ }
+ return inst->Next_3xx();
+}
+
static inline const Instruction* FindNextInstructionFollowingException(Thread* self,
ShadowFrame& shadow_frame,
uint32_t dex_pc,
@@ -699,11 +982,15 @@ static void UnexpectedOpcode(const Instruction* inst, MethodHelper& mh)
// Code to run before each dex instruction.
#define PREAMBLE()
-static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item,
+// TODO: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) which is failing due to template
+// specialization.
+template<bool do_access_check>
+static JValue ExecuteImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item,
ShadowFrame& shadow_frame, JValue result_register)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) __attribute__ ((hot));
+ NO_THREAD_SAFETY_ANALYSIS __attribute__ ((hot));
-static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item,
+template<bool do_access_check>
+static JValue ExecuteImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item,
ShadowFrame& shadow_frame, JValue result_register) {
if (UNLIKELY(!shadow_frame.HasReferenceArray())) {
LOG(FATAL) << "Invalid shadow frame for interpreter use";
@@ -716,12 +1003,14 @@ static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* c
// As the 'this' object won't change during the execution of current code, we
// want to cache it in local variables. Nevertheless, in order to let the
// garbage collector access it, we store it into sirt references.
- SirtRef<Object> this_object_ref(self, shadow_frame.GetThisObject());
+ SirtRef<Object> this_object_ref(self, shadow_frame.GetThisObject(code_item->ins_size_));
const Instruction* inst = Instruction::At(insns + shadow_frame.GetDexPC());
if (inst->GetDexPc(insns) == 0) { // We are entering the method as opposed to deoptimizing..
- instrumentation->MethodEnterEvent(self, this_object_ref.get(),
- shadow_frame.GetMethod(), 0);
+ if (UNLIKELY(instrumentation->HasMethodEntryListeners())) {
+ instrumentation->MethodEnterEvent(self, this_object_ref.get(),
+ shadow_frame.GetMethod(), 0);
+ }
}
while (true) {
if (UNLIKELY(self->TestAllFlags())) {
@@ -729,8 +1018,10 @@ static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* c
}
const uint32_t dex_pc = inst->GetDexPc(insns);
shadow_frame.SetDexPC(dex_pc);
- instrumentation->DexPcMovedEvent(self, this_object_ref.get(),
- shadow_frame.GetMethod(), dex_pc);
+ if (instrumentation->HasDexPcListeners()) {
+ instrumentation->DexPcMovedEvent(self, this_object_ref.get(),
+ shadow_frame.GetMethod(), dex_pc);
+ }
const bool kTracing = false;
if (kTracing) {
#define TRACE_LOG std::cerr
@@ -838,8 +1129,11 @@ static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* c
case Instruction::RETURN_VOID: {
PREAMBLE();
JValue result;
- instrumentation->MethodExitEvent(self, this_object_ref.get(),
- shadow_frame.GetMethod(), inst->GetDexPc(insns), result);
+ if (UNLIKELY(instrumentation->HasMethodExitListeners())) {
+ instrumentation->MethodExitEvent(self, this_object_ref.get(),
+ shadow_frame.GetMethod(), inst->GetDexPc(insns),
+ result);
+ }
return result;
}
case Instruction::RETURN: {
@@ -847,16 +1141,22 @@ static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* c
JValue result;
result.SetJ(0);
result.SetI(shadow_frame.GetVReg(inst->VRegA_11x()));
- instrumentation->MethodExitEvent(self, this_object_ref.get(),
- shadow_frame.GetMethod(), inst->GetDexPc(insns), result);
+ if (UNLIKELY(instrumentation->HasMethodExitListeners())) {
+ instrumentation->MethodExitEvent(self, this_object_ref.get(),
+ shadow_frame.GetMethod(), inst->GetDexPc(insns),
+ result);
+ }
return result;
}
case Instruction::RETURN_WIDE: {
PREAMBLE();
JValue result;
result.SetJ(shadow_frame.GetVRegLong(inst->VRegA_11x()));
- instrumentation->MethodExitEvent(self, this_object_ref.get(),
- shadow_frame.GetMethod(), inst->GetDexPc(insns), result);
+ if (UNLIKELY(instrumentation->HasMethodExitListeners())) {
+ instrumentation->MethodExitEvent(self, this_object_ref.get(),
+ shadow_frame.GetMethod(), inst->GetDexPc(insns),
+ result);
+ }
return result;
}
case Instruction::RETURN_OBJECT: {
@@ -864,14 +1164,17 @@ static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* c
JValue result;
result.SetJ(0);
result.SetL(shadow_frame.GetVRegReference(inst->VRegA_11x()));
- instrumentation->MethodExitEvent(self, this_object_ref.get(),
- shadow_frame.GetMethod(), inst->GetDexPc(insns), result);
+ if (UNLIKELY(instrumentation->HasMethodExitListeners())) {
+ instrumentation->MethodExitEvent(self, this_object_ref.get(),
+ shadow_frame.GetMethod(), inst->GetDexPc(insns),
+ result);
+ }
return result;
}
case Instruction::CONST_4: {
PREAMBLE();
uint32_t dst = inst->VRegA_11n();
- int32_t val = static_cast<int32_t>(inst->VRegB_11n() << 28) >> 28;
+ int32_t val = inst->VRegB_11n();
shadow_frame.SetVReg(dst, val);
if (val == 0) {
shadow_frame.SetVRegReference(dst, NULL);
@@ -882,7 +1185,7 @@ static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* c
case Instruction::CONST_16: {
PREAMBLE();
uint32_t dst = inst->VRegA_21s();
- int32_t val = static_cast<int16_t>(inst->VRegB_21s());
+ int32_t val = inst->VRegB_21s();
shadow_frame.SetVReg(dst, val);
if (val == 0) {
shadow_frame.SetVRegReference(dst, NULL);
@@ -904,7 +1207,7 @@ static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* c
case Instruction::CONST_HIGH16: {
PREAMBLE();
uint32_t dst = inst->VRegA_21h();
- int32_t val = inst->VRegB_21h() << 16;
+ int32_t val = static_cast<int32_t>(inst->VRegB_21h() << 16);
shadow_frame.SetVReg(dst, val);
if (val == 0) {
shadow_frame.SetVRegReference(dst, NULL);
@@ -914,14 +1217,12 @@ static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* c
}
case Instruction::CONST_WIDE_16:
PREAMBLE();
- shadow_frame.SetVRegLong(inst->VRegA_21s(),
- static_cast<int16_t>(inst->VRegB_21s()));
+ shadow_frame.SetVRegLong(inst->VRegA_21s(), inst->VRegB_21s());
inst = inst->Next_2xx();
break;
case Instruction::CONST_WIDE_32:
PREAMBLE();
- shadow_frame.SetVRegLong(inst->VRegA_31i(),
- static_cast<int32_t>(inst->VRegB_31i()));
+ shadow_frame.SetVRegLong(inst->VRegA_31i(), inst->VRegB_31i());
inst = inst->Next_3xx();
break;
case Instruction::CONST_WIDE:
@@ -959,7 +1260,7 @@ static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* c
case Instruction::CONST_CLASS: {
PREAMBLE();
Class* c = ResolveVerifyAndClinit(inst->VRegB_21c(), shadow_frame.GetMethod(),
- self, false, true);
+ self, false, do_access_check);
if (UNLIKELY(c == NULL)) {
HANDLE_PENDING_EXCEPTION();
} else {
@@ -995,7 +1296,7 @@ static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* c
case Instruction::CHECK_CAST: {
PREAMBLE();
Class* c = ResolveVerifyAndClinit(inst->VRegB_21c(), shadow_frame.GetMethod(),
- self, false, true);
+ self, false, do_access_check);
if (UNLIKELY(c == NULL)) {
HANDLE_PENDING_EXCEPTION();
} else {
@@ -1012,7 +1313,7 @@ static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* c
case Instruction::INSTANCE_OF: {
PREAMBLE();
Class* c = ResolveVerifyAndClinit(inst->VRegC_22c(), shadow_frame.GetMethod(),
- self, false, true);
+ self, false, do_access_check);
if (UNLIKELY(c == NULL)) {
HANDLE_PENDING_EXCEPTION();
} else {
@@ -1028,16 +1329,16 @@ static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* c
if (UNLIKELY(array == NULL)) {
ThrowNullPointerExceptionFromDexPC(shadow_frame.GetCurrentLocationForThrow());
HANDLE_PENDING_EXCEPTION();
- break;
+ } else {
+ shadow_frame.SetVReg(inst->VRegA_12x(), array->AsArray()->GetLength());
+ inst = inst->Next_1xx();
}
- shadow_frame.SetVReg(inst->VRegA_12x(), array->AsArray()->GetLength());
- inst = inst->Next_1xx();
break;
}
case Instruction::NEW_INSTANCE: {
PREAMBLE();
Object* obj = AllocObjectFromCode(inst->VRegB_21c(), shadow_frame.GetMethod(),
- self, true);
+ self, do_access_check);
if (UNLIKELY(obj == NULL)) {
HANDLE_PENDING_EXCEPTION();
} else {
@@ -1050,7 +1351,7 @@ static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* c
PREAMBLE();
int32_t length = shadow_frame.GetVReg(inst->VRegB_22c());
Object* obj = AllocArrayFromCode(inst->VRegC_22c(), shadow_frame.GetMethod(),
- length, self, true);
+ length, self, do_access_check);
if (UNLIKELY(obj == NULL)) {
HANDLE_PENDING_EXCEPTION();
} else {
@@ -1061,97 +1362,23 @@ static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* c
}
case Instruction::FILLED_NEW_ARRAY: {
PREAMBLE();
- const int32_t length = inst->VRegA_35c();
- CHECK(length <= 5);
- if (UNLIKELY(length < 0)) {
- ThrowNegativeArraySizeException(length);
- HANDLE_PENDING_EXCEPTION();
- break;
- }
- Class* arrayClass = ResolveVerifyAndClinit(inst->VRegB_35c(), shadow_frame.GetMethod(),
- self, false, true);
- if (UNLIKELY(arrayClass == NULL)) {
- HANDLE_PENDING_EXCEPTION();
- break;
- }
- CHECK(arrayClass->IsArrayClass());
- Class* componentClass = arrayClass->GetComponentType();
- if (UNLIKELY(componentClass->IsPrimitive() && !componentClass->IsPrimitiveInt())) {
- if (componentClass->IsPrimitiveLong() || componentClass->IsPrimitiveDouble()) {
- ThrowRuntimeException("Bad filled array request for type %s",
- PrettyDescriptor(componentClass).c_str());
- } else {
- self->ThrowNewExceptionF(shadow_frame.GetCurrentLocationForThrow(),
- "Ljava/lang/InternalError;",
- "Found type %s; filled-new-array not implemented for anything but \'int\'",
- PrettyDescriptor(componentClass).c_str());
- }
- HANDLE_PENDING_EXCEPTION();
- break;
- }
- Object* newArray = Array::Alloc(self, arrayClass, length);
- if (UNLIKELY(newArray == NULL)) {
- HANDLE_PENDING_EXCEPTION();
- } else {
- uint32_t arg[5];
- inst->GetArgs(arg);
- const bool is_primitive_int_component = componentClass->IsPrimitiveInt();
- for (int32_t i = 0; i < length; ++i) {
- if (is_primitive_int_component) {
- newArray->AsIntArray()->Set(i, shadow_frame.GetVReg(arg[i]));
- } else {
- newArray->AsObjectArray<Object>()->Set(i, shadow_frame.GetVRegReference(arg[i]));
- }
- }
- result_register.SetL(newArray);
+ bool success = DoFilledNewArray<false, do_access_check>(inst, shadow_frame,
+ self, &result_register);
+ if (LIKELY(success)) {
inst = inst->Next_3xx();
+ } else {
+ HANDLE_PENDING_EXCEPTION();
}
break;
}
case Instruction::FILLED_NEW_ARRAY_RANGE: {
PREAMBLE();
- int32_t length = inst->VRegA_3rc();
- if (UNLIKELY(length < 0)) {
- ThrowNegativeArraySizeException(length);
- HANDLE_PENDING_EXCEPTION();
- break;
- }
- Class* arrayClass = ResolveVerifyAndClinit(inst->VRegB_3rc(), shadow_frame.GetMethod(),
- self, false, true);
- if (UNLIKELY(arrayClass == NULL)) {
- HANDLE_PENDING_EXCEPTION();
- break;
- }
- CHECK(arrayClass->IsArrayClass());
- Class* componentClass = arrayClass->GetComponentType();
- if (UNLIKELY(componentClass->IsPrimitive() && !componentClass->IsPrimitiveInt())) {
- if (componentClass->IsPrimitiveLong() || componentClass->IsPrimitiveDouble()) {
- ThrowRuntimeException("Bad filled array request for type %s",
- PrettyDescriptor(componentClass).c_str());
- } else {
- self->ThrowNewExceptionF(shadow_frame.GetCurrentLocationForThrow(),
- "Ljava/lang/InternalError;",
- "Found type %s; filled-new-array not implemented for anything but \'int\'",
- PrettyDescriptor(componentClass).c_str());
- }
- HANDLE_PENDING_EXCEPTION();
- break;
- }
- Object* newArray = Array::Alloc(self, arrayClass, length);
- if (UNLIKELY(newArray == NULL)) {
- HANDLE_PENDING_EXCEPTION();
- } else {
- uint32_t vregC = inst->VRegC_3rc();
- const bool is_primitive_int_component = componentClass->IsPrimitiveInt();
- for (int32_t i = 0; i < length; ++i) {
- if (is_primitive_int_component) {
- newArray->AsIntArray()->Set(i, shadow_frame.GetVReg(vregC + i));
- } else {
- newArray->AsObjectArray<Object>()->Set(i, shadow_frame.GetVRegReference(vregC + i));
- }
- }
- result_register.SetL(newArray);
+ bool success = DoFilledNewArray<true, do_access_check>(inst, shadow_frame,
+ self, &result_register);
+ if (LIKELY(success)) {
inst = inst->Next_3xx();
+ } else {
+ HANDLE_PENDING_EXCEPTION();
}
break;
}
@@ -1165,8 +1392,9 @@ static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* c
}
Array* array = obj->AsArray();
DCHECK(array->IsArrayInstance() && !array->IsObjectArray());
+ const uint16_t* payload_addr = reinterpret_cast<const uint16_t*>(inst) + inst->VRegB_31t();
const Instruction::ArrayDataPayload* payload =
- reinterpret_cast<const Instruction::ArrayDataPayload*>(insns + inst->GetDexPc(insns) + inst->VRegB_31t());
+ reinterpret_cast<const Instruction::ArrayDataPayload*>(payload_addr);
if (UNLIKELY(static_cast<int32_t>(payload->element_count) > array->GetLength())) {
self->ThrowNewExceptionF(shadow_frame.GetCurrentLocationForThrow(),
"Ljava/lang/ArrayIndexOutOfBoundsException;",
@@ -1193,34 +1421,34 @@ static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* c
}
case Instruction::GOTO: {
PREAMBLE();
- inst = Instruction::At(insns + inst->GetDexPc(insns) + inst->VRegA_10t());
+ inst = inst->RelativeAt(inst->VRegA_10t());
break;
}
case Instruction::GOTO_16: {
PREAMBLE();
- inst = Instruction::At(insns + inst->GetDexPc(insns) + inst->VRegA_20t());
+ inst = inst->RelativeAt(inst->VRegA_20t());
break;
}
case Instruction::GOTO_32: {
PREAMBLE();
- inst = Instruction::At(insns + inst->GetDexPc(insns) + inst->VRegA_30t());
+ inst = inst->RelativeAt(inst->VRegA_30t());
break;
}
case Instruction::PACKED_SWITCH: {
PREAMBLE();
- const uint16_t* switch_data = insns + inst->GetDexPc(insns) + inst->VRegB_31t();
+ const uint16_t* switch_data = reinterpret_cast<const uint16_t*>(inst) + inst->VRegB_31t();
int32_t test_val = shadow_frame.GetVReg(inst->VRegA_31t());
DCHECK_EQ(switch_data[0], static_cast<uint16_t>(Instruction::kPackedSwitchSignature));
uint16_t size = switch_data[1];
DCHECK_GT(size, 0);
const int32_t* keys = reinterpret_cast<const int32_t*>(&switch_data[2]);
- CHECK(IsAligned<4>(keys));
+ DCHECK(IsAligned<4>(keys));
int32_t first_key = keys[0];
const int32_t* targets = reinterpret_cast<const int32_t*>(&switch_data[4]);
DCHECK(IsAligned<4>(targets));
int32_t index = test_val - first_key;
if (index >= 0 && index < size) {
- inst = Instruction::At(insns + inst->GetDexPc(insns) + targets[index]);
+ inst = inst->RelativeAt(targets[index]);
} else {
inst = inst->Next_3xx();
}
@@ -1228,31 +1456,7 @@ static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* c
}
case Instruction::SPARSE_SWITCH: {
PREAMBLE();
- uint32_t dex_pc = inst->GetDexPc(insns);
- const uint16_t* switch_data = insns + dex_pc + inst->VRegB_31t();
- int32_t test_val = shadow_frame.GetVReg(inst->VRegA_31t());
- CHECK_EQ(switch_data[0], static_cast<uint16_t>(Instruction::kSparseSwitchSignature));
- uint16_t size = switch_data[1];
- CHECK_GT(size, 0);
- const int32_t* keys = reinterpret_cast<const int32_t*>(&switch_data[2]);
- CHECK(IsAligned<4>(keys));
- const int32_t* entries = keys + size;
- CHECK(IsAligned<4>(entries));
- int lo = 0;
- int hi = size - 1;
- inst = inst->Next_3xx();
- while (lo <= hi) {
- int mid = (lo + hi) / 2;
- int32_t foundVal = keys[mid];
- if (test_val < foundVal) {
- hi = mid - 1;
- } else if (test_val > foundVal) {
- lo = mid + 1;
- } else {
- inst = Instruction::At(insns + dex_pc + entries[mid]);
- break;
- }
- }
+ inst = DoSparseSwitch(inst, shadow_frame);
break;
}
case Instruction::CMPL_FLOAT: {
@@ -1339,7 +1543,7 @@ static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* c
case Instruction::IF_EQ: {
PREAMBLE();
if (shadow_frame.GetVReg(inst->VRegA_22t()) == shadow_frame.GetVReg(inst->VRegB_22t())) {
- inst = Instruction::At(insns + inst->GetDexPc(insns) + inst->VRegC_22t());
+ inst = inst->RelativeAt(inst->VRegC_22t());
} else {
inst = inst->Next_2xx();
}
@@ -1348,7 +1552,7 @@ static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* c
case Instruction::IF_NE: {
PREAMBLE();
if (shadow_frame.GetVReg(inst->VRegA_22t()) != shadow_frame.GetVReg(inst->VRegB_22t())) {
- inst = Instruction::At(insns + inst->GetDexPc(insns) + inst->VRegC_22t());
+ inst = inst->RelativeAt(inst->VRegC_22t());
} else {
inst = inst->Next_2xx();
}
@@ -1357,7 +1561,7 @@ static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* c
case Instruction::IF_LT: {
PREAMBLE();
if (shadow_frame.GetVReg(inst->VRegA_22t()) < shadow_frame.GetVReg(inst->VRegB_22t())) {
- inst = Instruction::At(insns + inst->GetDexPc(insns) + inst->VRegC_22t());
+ inst = inst->RelativeAt(inst->VRegC_22t());
} else {
inst = inst->Next_2xx();
}
@@ -1366,7 +1570,7 @@ static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* c
case Instruction::IF_GE: {
PREAMBLE();
if (shadow_frame.GetVReg(inst->VRegA_22t()) >= shadow_frame.GetVReg(inst->VRegB_22t())) {
- inst = Instruction::At(insns + inst->GetDexPc(insns) + inst->VRegC_22t());
+ inst = inst->RelativeAt(inst->VRegC_22t());
} else {
inst = inst->Next_2xx();
}
@@ -1375,7 +1579,7 @@ static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* c
case Instruction::IF_GT: {
PREAMBLE();
if (shadow_frame.GetVReg(inst->VRegA_22t()) > shadow_frame.GetVReg(inst->VRegB_22t())) {
- inst = Instruction::At(insns + inst->GetDexPc(insns) + inst->VRegC_22t());
+ inst = inst->RelativeAt(inst->VRegC_22t());
} else {
inst = inst->Next_2xx();
}
@@ -1384,7 +1588,7 @@ static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* c
case Instruction::IF_LE: {
PREAMBLE();
if (shadow_frame.GetVReg(inst->VRegA_22t()) <= shadow_frame.GetVReg(inst->VRegB_22t())) {
- inst = Instruction::At(insns + inst->GetDexPc(insns) + inst->VRegC_22t());
+ inst = inst->RelativeAt(inst->VRegC_22t());
} else {
inst = inst->Next_2xx();
}
@@ -1393,7 +1597,7 @@ static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* c
case Instruction::IF_EQZ: {
PREAMBLE();
if (shadow_frame.GetVReg(inst->VRegA_21t()) == 0) {
- inst = Instruction::At(insns + inst->GetDexPc(insns) + inst->VRegB_21t());
+ inst = inst->RelativeAt(inst->VRegB_21t());
} else {
inst = inst->Next_2xx();
}
@@ -1402,7 +1606,7 @@ static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* c
case Instruction::IF_NEZ: {
PREAMBLE();
if (shadow_frame.GetVReg(inst->VRegA_21t()) != 0) {
- inst = Instruction::At(insns + inst->GetDexPc(insns) + inst->VRegB_21t());
+ inst = inst->RelativeAt(inst->VRegB_21t());
} else {
inst = inst->Next_2xx();
}
@@ -1411,7 +1615,7 @@ static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* c
case Instruction::IF_LTZ: {
PREAMBLE();
if (shadow_frame.GetVReg(inst->VRegA_21t()) < 0) {
- inst = Instruction::At(insns + inst->GetDexPc(insns) + inst->VRegB_21t());
+ inst = inst->RelativeAt(inst->VRegB_21t());
} else {
inst = inst->Next_2xx();
}
@@ -1420,7 +1624,7 @@ static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* c
case Instruction::IF_GEZ: {
PREAMBLE();
if (shadow_frame.GetVReg(inst->VRegA_21t()) >= 0) {
- inst = Instruction::At(insns + inst->GetDexPc(insns) + inst->VRegB_21t());
+ inst = inst->RelativeAt(inst->VRegB_21t());
} else {
inst = inst->Next_2xx();
}
@@ -1429,7 +1633,7 @@ static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* c
case Instruction::IF_GTZ: {
PREAMBLE();
if (shadow_frame.GetVReg(inst->VRegA_21t()) > 0) {
- inst = Instruction::At(insns + inst->GetDexPc(insns) + inst->VRegB_21t());
+ inst = inst->RelativeAt(inst->VRegB_21t());
} else {
inst = inst->Next_2xx();
}
@@ -1438,7 +1642,7 @@ static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* c
case Instruction::IF_LEZ: {
PREAMBLE();
if (shadow_frame.GetVReg(inst->VRegA_21t()) <= 0) {
- inst = Instruction::At(insns + inst->GetDexPc(insns) + inst->VRegB_21t());
+ inst = inst->RelativeAt(inst->VRegB_21t());
} else {
inst = inst->Next_2xx();
}
@@ -1705,192 +1909,232 @@ static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* c
}
case Instruction::IGET_BOOLEAN:
PREAMBLE();
- DoFieldGet(self, shadow_frame, inst, InstancePrimitiveRead, Primitive::kPrimBoolean);
+ DoFieldGet<InstancePrimitiveRead, Primitive::kPrimBoolean, do_access_check>(self, shadow_frame, inst);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
break;
case Instruction::IGET_BYTE:
PREAMBLE();
- DoFieldGet(self, shadow_frame, inst, InstancePrimitiveRead, Primitive::kPrimByte);
+ DoFieldGet<InstancePrimitiveRead, Primitive::kPrimByte, do_access_check>(self, shadow_frame, inst);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
break;
case Instruction::IGET_CHAR:
PREAMBLE();
- DoFieldGet(self, shadow_frame, inst, InstancePrimitiveRead, Primitive::kPrimChar);
+ DoFieldGet<InstancePrimitiveRead, Primitive::kPrimChar, do_access_check>(self, shadow_frame, inst);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
break;
case Instruction::IGET_SHORT:
PREAMBLE();
- DoFieldGet(self, shadow_frame, inst, InstancePrimitiveRead, Primitive::kPrimShort);
+ DoFieldGet<InstancePrimitiveRead, Primitive::kPrimShort, do_access_check>(self, shadow_frame, inst);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
break;
case Instruction::IGET:
PREAMBLE();
- DoFieldGet(self, shadow_frame, inst, InstancePrimitiveRead, Primitive::kPrimInt);
+ DoFieldGet<InstancePrimitiveRead, Primitive::kPrimInt, do_access_check>(self, shadow_frame, inst);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
break;
case Instruction::IGET_WIDE:
PREAMBLE();
- DoFieldGet(self, shadow_frame, inst, InstancePrimitiveRead, Primitive::kPrimLong);
+ DoFieldGet<InstancePrimitiveRead, Primitive::kPrimLong, do_access_check>(self, shadow_frame, inst);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
break;
case Instruction::IGET_OBJECT:
PREAMBLE();
- DoFieldGet(self, shadow_frame, inst, InstanceObjectRead, Primitive::kPrimNot);
+ DoFieldGet<InstanceObjectRead, Primitive::kPrimNot, do_access_check>(self, shadow_frame, inst);
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
+ break;
+ case Instruction::IGET_QUICK:
+ PREAMBLE();
+ DoIGetQuick<Primitive::kPrimInt>(self, shadow_frame, inst);
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
+ break;
+ case Instruction::IGET_WIDE_QUICK:
+ PREAMBLE();
+ DoIGetQuick<Primitive::kPrimLong>(self, shadow_frame, inst);
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
+ break;
+ case Instruction::IGET_OBJECT_QUICK:
+ PREAMBLE();
+ DoIGetQuick<Primitive::kPrimNot>(self, shadow_frame, inst);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
break;
case Instruction::SGET_BOOLEAN:
PREAMBLE();
- DoFieldGet(self, shadow_frame, inst, StaticPrimitiveRead, Primitive::kPrimBoolean);
+ DoFieldGet<StaticPrimitiveRead, Primitive::kPrimBoolean, do_access_check>(self, shadow_frame, inst);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
break;
case Instruction::SGET_BYTE:
PREAMBLE();
- DoFieldGet(self, shadow_frame, inst, StaticPrimitiveRead, Primitive::kPrimByte);
+ DoFieldGet<StaticPrimitiveRead, Primitive::kPrimByte, do_access_check>(self, shadow_frame, inst);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
break;
case Instruction::SGET_CHAR:
PREAMBLE();
- DoFieldGet(self, shadow_frame, inst, StaticPrimitiveRead, Primitive::kPrimChar);
+ DoFieldGet<StaticPrimitiveRead, Primitive::kPrimChar, do_access_check>(self, shadow_frame, inst);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
break;
case Instruction::SGET_SHORT:
PREAMBLE();
- DoFieldGet(self, shadow_frame, inst, StaticPrimitiveRead, Primitive::kPrimShort);
+ DoFieldGet<StaticPrimitiveRead, Primitive::kPrimShort, do_access_check>(self, shadow_frame, inst);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
break;
case Instruction::SGET:
PREAMBLE();
- DoFieldGet(self, shadow_frame, inst, StaticPrimitiveRead, Primitive::kPrimInt);
+ DoFieldGet<StaticPrimitiveRead, Primitive::kPrimInt, do_access_check>(self, shadow_frame, inst);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
break;
case Instruction::SGET_WIDE:
PREAMBLE();
- DoFieldGet(self, shadow_frame, inst, StaticPrimitiveRead, Primitive::kPrimLong);
+ DoFieldGet<StaticPrimitiveRead, Primitive::kPrimLong, do_access_check>(self, shadow_frame, inst);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
break;
case Instruction::SGET_OBJECT:
PREAMBLE();
- DoFieldGet(self, shadow_frame, inst, StaticObjectRead, Primitive::kPrimNot);
+ DoFieldGet<StaticObjectRead, Primitive::kPrimNot, do_access_check>(self, shadow_frame, inst);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
break;
case Instruction::IPUT_BOOLEAN:
PREAMBLE();
- DoFieldPut(self, shadow_frame, inst, InstancePrimitiveWrite, Primitive::kPrimBoolean);
+ DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimBoolean, do_access_check>(self, shadow_frame, inst);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
break;
case Instruction::IPUT_BYTE:
PREAMBLE();
- DoFieldPut(self, shadow_frame, inst, InstancePrimitiveWrite, Primitive::kPrimByte);
+ DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimByte, do_access_check>(self, shadow_frame, inst);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
break;
case Instruction::IPUT_CHAR:
PREAMBLE();
- DoFieldPut(self, shadow_frame, inst, InstancePrimitiveWrite, Primitive::kPrimChar);
+ DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimChar, do_access_check>(self, shadow_frame, inst);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
break;
case Instruction::IPUT_SHORT:
PREAMBLE();
- DoFieldPut(self, shadow_frame, inst, InstancePrimitiveWrite, Primitive::kPrimShort);
+ DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimShort, do_access_check>(self, shadow_frame, inst);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
break;
case Instruction::IPUT:
PREAMBLE();
- DoFieldPut(self, shadow_frame, inst, InstancePrimitiveWrite, Primitive::kPrimInt);
+ DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimInt, do_access_check>(self, shadow_frame, inst);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
break;
case Instruction::IPUT_WIDE:
PREAMBLE();
- DoFieldPut(self, shadow_frame, inst, InstancePrimitiveWrite, Primitive::kPrimLong);
+ DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimLong, do_access_check>(self, shadow_frame, inst);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
break;
case Instruction::IPUT_OBJECT:
PREAMBLE();
- DoFieldPut(self, shadow_frame, inst, InstanceObjectWrite, Primitive::kPrimNot);
+ DoFieldPut<InstanceObjectWrite, Primitive::kPrimNot, do_access_check>(self, shadow_frame, inst);
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
+ break;
+ case Instruction::IPUT_QUICK:
+ PREAMBLE();
+ DoIPutQuick<Primitive::kPrimInt>(self, shadow_frame, inst);
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
+ break;
+ case Instruction::IPUT_WIDE_QUICK:
+ PREAMBLE();
+ DoIPutQuick<Primitive::kPrimLong>(self, shadow_frame, inst);
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
+ break;
+ case Instruction::IPUT_OBJECT_QUICK:
+ PREAMBLE();
+ DoIPutQuick<Primitive::kPrimNot>(self, shadow_frame, inst);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
break;
case Instruction::SPUT_BOOLEAN:
PREAMBLE();
- DoFieldPut(self, shadow_frame, inst, StaticPrimitiveWrite, Primitive::kPrimBoolean);
+ DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimBoolean, do_access_check>(self, shadow_frame, inst);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
break;
case Instruction::SPUT_BYTE:
PREAMBLE();
- DoFieldPut(self, shadow_frame, inst, StaticPrimitiveWrite, Primitive::kPrimByte);
+ DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimByte, do_access_check>(self, shadow_frame, inst);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
break;
case Instruction::SPUT_CHAR:
PREAMBLE();
- DoFieldPut(self, shadow_frame, inst, StaticPrimitiveWrite, Primitive::kPrimChar);
+ DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimChar, do_access_check>(self, shadow_frame, inst);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
break;
case Instruction::SPUT_SHORT:
PREAMBLE();
- DoFieldPut(self, shadow_frame, inst, StaticPrimitiveWrite, Primitive::kPrimShort);
+ DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimShort, do_access_check>(self, shadow_frame, inst);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
break;
case Instruction::SPUT:
PREAMBLE();
- DoFieldPut(self, shadow_frame, inst, StaticPrimitiveWrite, Primitive::kPrimInt);
+ DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimInt, do_access_check>(self, shadow_frame, inst);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
break;
case Instruction::SPUT_WIDE:
PREAMBLE();
- DoFieldPut(self, shadow_frame, inst, StaticPrimitiveWrite, Primitive::kPrimLong);
+ DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimLong, do_access_check>(self, shadow_frame, inst);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
break;
case Instruction::SPUT_OBJECT:
PREAMBLE();
- DoFieldPut(self, shadow_frame, inst, StaticObjectWrite, Primitive::kPrimNot);
+ DoFieldPut<StaticObjectWrite, Primitive::kPrimNot, do_access_check>(self, shadow_frame, inst);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
break;
case Instruction::INVOKE_VIRTUAL:
PREAMBLE();
- DoInvoke(self, mh, shadow_frame, inst, kVirtual, false, &result_register);
+ DoInvoke<kVirtual, false, do_access_check>(self, shadow_frame, inst, &result_register);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_3xx);
break;
case Instruction::INVOKE_VIRTUAL_RANGE:
PREAMBLE();
- DoInvoke(self, mh, shadow_frame, inst, kVirtual, true, &result_register);
+ DoInvoke<kVirtual, true, do_access_check>(self, shadow_frame, inst, &result_register);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_3xx);
break;
case Instruction::INVOKE_SUPER:
PREAMBLE();
- DoInvoke(self, mh, shadow_frame, inst, kSuper, false, &result_register);
+ DoInvoke<kSuper, false, do_access_check>(self, shadow_frame, inst, &result_register);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_3xx);
break;
case Instruction::INVOKE_SUPER_RANGE:
PREAMBLE();
- DoInvoke(self, mh, shadow_frame, inst, kSuper, true, &result_register);
+ DoInvoke<kSuper, true, do_access_check>(self, shadow_frame, inst, &result_register);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_3xx);
break;
case Instruction::INVOKE_DIRECT:
PREAMBLE();
- DoInvoke(self, mh, shadow_frame, inst, kDirect, false, &result_register);
+ DoInvoke<kDirect, false, do_access_check>(self, shadow_frame, inst, &result_register);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_3xx);
break;
case Instruction::INVOKE_DIRECT_RANGE:
PREAMBLE();
- DoInvoke(self, mh, shadow_frame, inst, kDirect, true, &result_register);
+ DoInvoke<kDirect, true, do_access_check>(self, shadow_frame, inst, &result_register);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_3xx);
break;
case Instruction::INVOKE_INTERFACE:
PREAMBLE();
- DoInvoke(self, mh, shadow_frame, inst, kInterface, false, &result_register);
+ DoInvoke<kInterface, false, do_access_check>(self, shadow_frame, inst, &result_register);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_3xx);
break;
case Instruction::INVOKE_INTERFACE_RANGE:
PREAMBLE();
- DoInvoke(self, mh, shadow_frame, inst, kInterface, true, &result_register);
+ DoInvoke<kInterface, true, do_access_check>(self, shadow_frame, inst, &result_register);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_3xx);
break;
case Instruction::INVOKE_STATIC:
PREAMBLE();
- DoInvoke(self, mh, shadow_frame, inst, kStatic, false, &result_register);
+ DoInvoke<kStatic, false, do_access_check>(self, shadow_frame, inst, &result_register);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_3xx);
break;
case Instruction::INVOKE_STATIC_RANGE:
PREAMBLE();
- DoInvoke(self, mh, shadow_frame, inst, kStatic, true, &result_register);
+ DoInvoke<kStatic, true, do_access_check>(self, shadow_frame, inst, &result_register);
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_3xx);
+ break;
+ case Instruction::INVOKE_VIRTUAL_QUICK:
+ PREAMBLE();
+ DoInvokeVirtualQuick<false>(self, shadow_frame, inst, &result_register);
+ POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_3xx);
+ break;
+ case Instruction::INVOKE_VIRTUAL_RANGE_QUICK:
+ PREAMBLE();
+ DoInvokeVirtualQuick<true>(self, shadow_frame, inst, &result_register);
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_3xx);
break;
case Instruction::NEG_INT:
@@ -1955,33 +2199,35 @@ static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* c
break;
case Instruction::FLOAT_TO_INT: {
PREAMBLE();
- uint32_t dst = inst->VRegA_12x();
float val = shadow_frame.GetVRegFloat(inst->VRegB_12x());
+ int32_t result;
if (val != val) {
- shadow_frame.SetVReg(dst, 0);
+ result = 0;
} else if (val > static_cast<float>(kMaxInt)) {
- shadow_frame.SetVReg(dst, kMaxInt);
+ result = kMaxInt;
} else if (val < static_cast<float>(kMinInt)) {
- shadow_frame.SetVReg(dst, kMinInt);
+ result = kMinInt;
} else {
- shadow_frame.SetVReg(dst, val);
+ result = val;
}
+ shadow_frame.SetVReg(inst->VRegA_12x(), result);
inst = inst->Next_1xx();
break;
}
case Instruction::FLOAT_TO_LONG: {
PREAMBLE();
- uint32_t dst = inst->VRegA_12x();
float val = shadow_frame.GetVRegFloat(inst->VRegB_12x());
+ int64_t result;
if (val != val) {
- shadow_frame.SetVRegLong(dst, 0);
+ result = 0;
} else if (val > static_cast<float>(kMaxLong)) {
- shadow_frame.SetVRegLong(dst, kMaxLong);
+ result = kMaxLong;
} else if (val < static_cast<float>(kMinLong)) {
- shadow_frame.SetVRegLong(dst, kMinLong);
+ result = kMinLong;
} else {
- shadow_frame.SetVRegLong(dst, val);
+ result = val;
}
+ shadow_frame.SetVRegLong(inst->VRegA_12x(), result);
inst = inst->Next_1xx();
break;
}
@@ -1992,33 +2238,35 @@ static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* c
break;
case Instruction::DOUBLE_TO_INT: {
PREAMBLE();
- uint32_t dst = inst->VRegA_12x();
double val = shadow_frame.GetVRegDouble(inst->VRegB_12x());
+ int32_t result;
if (val != val) {
- shadow_frame.SetVReg(dst, 0);
+ result = 0;
} else if (val > static_cast<double>(kMaxInt)) {
- shadow_frame.SetVReg(dst, kMaxInt);
+ result = kMaxInt;
} else if (val < static_cast<double>(kMinInt)) {
- shadow_frame.SetVReg(dst, kMinInt);
+ result = kMinInt;
} else {
- shadow_frame.SetVReg(dst, val);
+ result = val;
}
+ shadow_frame.SetVReg(inst->VRegA_12x(), result);
inst = inst->Next_1xx();
break;
}
case Instruction::DOUBLE_TO_LONG: {
PREAMBLE();
- uint32_t dst = inst->VRegA_12x();
double val = shadow_frame.GetVRegDouble(inst->VRegB_12x());
+ int64_t result;
if (val != val) {
- shadow_frame.SetVRegLong(dst, 0);
+ result = 0;
} else if (val > static_cast<double>(kMaxLong)) {
- shadow_frame.SetVRegLong(dst, kMaxLong);
+ result = kMaxLong;
} else if (val < static_cast<double>(kMinLong)) {
- shadow_frame.SetVRegLong(dst, kMinLong);
+ result = kMinLong;
} else {
- shadow_frame.SetVRegLong(dst, val);
+ result = val;
}
+ shadow_frame.SetVRegLong(inst->VRegA_12x(), result);
inst = inst->Next_1xx();
break;
}
@@ -2068,14 +2316,14 @@ static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* c
break;
case Instruction::DIV_INT:
PREAMBLE();
- DoIntDivide(self, shadow_frame, inst->VRegA_23x(),
+ DoIntDivide(shadow_frame, inst->VRegA_23x(),
shadow_frame.GetVReg(inst->VRegB_23x()),
shadow_frame.GetVReg(inst->VRegC_23x()));
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
break;
case Instruction::REM_INT:
PREAMBLE();
- DoIntRemainder(self, shadow_frame, inst->VRegA_23x(),
+ DoIntRemainder(shadow_frame, inst->VRegA_23x(),
shadow_frame.GetVReg(inst->VRegB_23x()),
shadow_frame.GetVReg(inst->VRegC_23x()));
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
@@ -2145,14 +2393,14 @@ static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* c
break;
case Instruction::DIV_LONG:
PREAMBLE();
- DoLongDivide(self, shadow_frame, inst->VRegA_23x(),
+ DoLongDivide(shadow_frame, inst->VRegA_23x(),
shadow_frame.GetVRegLong(inst->VRegB_23x()),
shadow_frame.GetVRegLong(inst->VRegC_23x()));
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
break;
case Instruction::REM_LONG:
PREAMBLE();
- DoLongRemainder(self, shadow_frame, inst->VRegA_23x(),
+ DoLongRemainder(shadow_frame, inst->VRegA_23x(),
shadow_frame.GetVRegLong(inst->VRegB_23x()),
shadow_frame.GetVRegLong(inst->VRegC_23x()));
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
@@ -2296,10 +2544,18 @@ static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* c
inst = inst->Next_1xx();
break;
}
+ case Instruction::DIV_INT_2ADDR: {
+ PREAMBLE();
+ uint32_t vregA = inst->VRegA_12x();
+ DoIntDivide(shadow_frame, vregA, shadow_frame.GetVReg(vregA),
+ shadow_frame.GetVReg(inst->VRegB_12x()));
+ inst = inst->Next_1xx();
+ break;
+ }
case Instruction::REM_INT_2ADDR: {
PREAMBLE();
uint32_t vregA = inst->VRegA_12x();
- DoIntRemainder(self, shadow_frame, vregA, shadow_frame.GetVReg(vregA),
+ DoIntRemainder(shadow_frame, vregA, shadow_frame.GetVReg(vregA),
shadow_frame.GetVReg(inst->VRegB_12x()));
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_1xx);
break;
@@ -2358,14 +2614,6 @@ static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* c
inst = inst->Next_1xx();
break;
}
- case Instruction::DIV_INT_2ADDR: {
- PREAMBLE();
- uint32_t vregA = inst->VRegA_12x();
- DoIntDivide(self, shadow_frame, vregA, shadow_frame.GetVReg(vregA),
- shadow_frame.GetVReg(inst->VRegB_12x()));
- inst = inst->Next_1xx();
- break;
- }
case Instruction::ADD_LONG_2ADDR: {
PREAMBLE();
uint32_t vregA = inst->VRegA_12x();
@@ -2396,7 +2644,7 @@ static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* c
case Instruction::DIV_LONG_2ADDR: {
PREAMBLE();
uint32_t vregA = inst->VRegA_12x();
- DoLongDivide(self, shadow_frame, vregA, shadow_frame.GetVRegLong(vregA),
+ DoLongDivide(shadow_frame, vregA, shadow_frame.GetVRegLong(vregA),
shadow_frame.GetVRegLong(inst->VRegB_12x()));
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_1xx);
break;
@@ -2404,7 +2652,7 @@ static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* c
case Instruction::REM_LONG_2ADDR: {
PREAMBLE();
uint32_t vregA = inst->VRegA_12x();
- DoLongRemainder(self, shadow_frame, vregA, shadow_frame.GetVRegLong(vregA),
+ DoLongRemainder(shadow_frame, vregA, shadow_frame.GetVRegLong(vregA),
shadow_frame.GetVRegLong(inst->VRegB_12x()));
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_1xx);
break;
@@ -2576,13 +2824,13 @@ static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* c
break;
case Instruction::DIV_INT_LIT16:
PREAMBLE();
- DoIntDivide(self, shadow_frame, inst->VRegA_22s(),
+ DoIntDivide(shadow_frame, inst->VRegA_22s(),
shadow_frame.GetVReg(inst->VRegB_22s()), inst->VRegC_22s());
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
break;
case Instruction::REM_INT_LIT16:
PREAMBLE();
- DoIntRemainder(self, shadow_frame, inst->VRegA_22s(),
+ DoIntRemainder(shadow_frame, inst->VRegA_22s(),
shadow_frame.GetVReg(inst->VRegB_22s()), inst->VRegC_22s());
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
break;
@@ -2630,13 +2878,13 @@ static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* c
break;
case Instruction::DIV_INT_LIT8:
PREAMBLE();
- DoIntDivide(self, shadow_frame, inst->VRegA_22b(),
+ DoIntDivide(shadow_frame, inst->VRegA_22b(),
shadow_frame.GetVReg(inst->VRegB_22b()), inst->VRegC_22b());
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
break;
case Instruction::REM_INT_LIT8:
PREAMBLE();
- DoIntRemainder(self, shadow_frame, inst->VRegA_22b(),
+ DoIntRemainder(shadow_frame, inst->VRegA_22b(),
shadow_frame.GetVReg(inst->VRegB_22b()), inst->VRegC_22b());
POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
break;
@@ -2683,7 +2931,7 @@ static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* c
inst = inst->Next_2xx();
break;
case Instruction::UNUSED_3E ... Instruction::UNUSED_43:
- case Instruction::UNUSED_E3 ... Instruction::UNUSED_FF:
+ case Instruction::UNUSED_EB ... Instruction::UNUSED_FF:
case Instruction::UNUSED_73:
case Instruction::UNUSED_79:
case Instruction::UNUSED_7A:
@@ -2692,10 +2940,25 @@ static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* c
}
}
+static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item,
+ ShadowFrame& shadow_frame, JValue result_register)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+static inline JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item,
+ ShadowFrame& shadow_frame, JValue result_register) {
+ if (shadow_frame.GetMethod()->IsPreverified()) {
+ // Enter the "without access check" interpreter.
+ return ExecuteImpl<false>(self, mh, code_item, shadow_frame, result_register);
+ } else {
+ // Enter the "with access check" interpreter.
+ return ExecuteImpl<true>(self, mh, code_item, shadow_frame, result_register);
+ }
+}
+
void EnterInterpreterFromInvoke(Thread* self, AbstractMethod* method, Object* receiver,
uint32_t* args, JValue* result) {
DCHECK_EQ(self, Thread::Current());
- if (__builtin_frame_address(0) < self->GetStackEnd()) {
+ if (UNLIKELY(__builtin_frame_address(0) < self->GetStackEnd())) {
ThrowStackOverflowError(self);
return;
}
@@ -2799,7 +3062,7 @@ JValue EnterInterpreterFromStub(Thread* self, MethodHelper& mh, const DexFile::C
ShadowFrame& shadow_frame)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
DCHECK_EQ(self, Thread::Current());
- if (__builtin_frame_address(0) < self->GetStackEnd()) {
+ if (UNLIKELY(__builtin_frame_address(0) < self->GetStackEnd())) {
ThrowStackOverflowError(self);
return JValue();
}
@@ -2807,9 +3070,11 @@ JValue EnterInterpreterFromStub(Thread* self, MethodHelper& mh, const DexFile::C
return Execute(self, mh, code_item, shadow_frame, JValue());
}
-void EnterInterpreterFromInterpreter(Thread* self, ShadowFrame* shadow_frame, JValue* result)
+void artInterpreterToInterpreterEntry(Thread* self, MethodHelper& mh,
+ const DexFile::CodeItem* code_item,
+ ShadowFrame* shadow_frame, JValue* result)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- if (__builtin_frame_address(0) < self->GetStackEnd()) {
+ if (UNLIKELY(__builtin_frame_address(0) < self->GetStackEnd())) {
ThrowStackOverflowError(self);
return;
}
@@ -2826,8 +3091,6 @@ void EnterInterpreterFromInterpreter(Thread* self, ShadowFrame* shadow_frame, JV
self->PushShadowFrame(shadow_frame);
- MethodHelper mh(method);
- const DexFile::CodeItem* code_item = mh.GetCodeItem();
if (LIKELY(!method->IsNative())) {
result->SetJ(Execute(self, mh, code_item, *shadow_frame, JValue()).GetJ());
} else {
diff --git a/src/interpreter/interpreter.h b/src/interpreter/interpreter.h
index 96fa05034e..20166ac545 100644
--- a/src/interpreter/interpreter.h
+++ b/src/interpreter/interpreter.h
@@ -47,7 +47,9 @@ extern JValue EnterInterpreterFromStub(Thread* self, MethodHelper& mh,
ShadowFrame& shadow_frame)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-extern void EnterInterpreterFromInterpreter(Thread* self, ShadowFrame* shadow_frame, JValue* result)
+extern "C" void artInterpreterToInterpreterEntry(Thread* self, MethodHelper& mh,
+ const DexFile::CodeItem* code_item,
+ ShadowFrame* shadow_frame, JValue* result)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
} // namespace interpreter
diff --git a/src/jni_internal.cc b/src/jni_internal.cc
index 2673074302..e457edcd8f 100644
--- a/src/jni_internal.cc
+++ b/src/jni_internal.cc
@@ -28,7 +28,7 @@
#include "base/stringpiece.h"
#include "class_linker.h"
#include "dex_file-inl.h"
-#include "gc/card_table-inl.h"
+#include "gc/accounting/card_table-inl.h"
#include "invoke_arg_array_builder.h"
#include "jni.h"
#include "mirror/class-inl.h"
diff --git a/src/jni_internal_test.cc b/src/jni_internal_test.cc
index 0f584444e5..c8b9eb95e3 100644
--- a/src/jni_internal_test.cc
+++ b/src/jni_internal_test.cc
@@ -16,6 +16,7 @@
#include "jni_internal.h"
+#include <limits.h>
#include <cfloat>
#include <cmath>
diff --git a/src/locks.cc b/src/locks.cc
index eb0620c0c3..51a40c383a 100644
--- a/src/locks.cc
+++ b/src/locks.cc
@@ -22,7 +22,7 @@ namespace art {
Mutex* Locks::abort_lock_ = NULL;
Mutex* Locks::breakpoint_lock_ = NULL;
-Mutex* Locks::classlinker_classes_lock_ = NULL;
+ReaderWriterMutex* Locks::classlinker_classes_lock_ = NULL;
ReaderWriterMutex* Locks::heap_bitmap_lock_ = NULL;
Mutex* Locks::logging_lock_ = NULL;
ReaderWriterMutex* Locks::mutator_lock_ = NULL;
@@ -52,7 +52,8 @@ void Locks::Init() {
DCHECK(breakpoint_lock_ == NULL);
breakpoint_lock_ = new Mutex("breakpoint lock", kBreakpointLock);
DCHECK(classlinker_classes_lock_ == NULL);
- classlinker_classes_lock_ = new Mutex("ClassLinker classes lock", kClassLinkerClassesLock);
+ classlinker_classes_lock_ = new ReaderWriterMutex("ClassLinker classes lock",
+ kClassLinkerClassesLock);
DCHECK(heap_bitmap_lock_ == NULL);
heap_bitmap_lock_ = new ReaderWriterMutex("heap bitmap lock", kHeapBitmapLock);
DCHECK(mutator_lock_ == NULL);
diff --git a/src/locks.h b/src/locks.h
index 431a14816a..202fa025a3 100644
--- a/src/locks.h
+++ b/src/locks.h
@@ -36,9 +36,9 @@ enum LockLevel {
kUnexpectedSignalLock,
kThreadSuspendCountLock,
kAbortLock,
+ kAllocSpaceLock,
kDefaultMutexLevel,
kJdwpSerialLock,
- kAllocSpaceLock,
kMarkSweepLargeObjectLock,
kPinTableLock,
kLoadLibraryLock,
@@ -143,7 +143,7 @@ class Locks {
static Mutex* trace_lock_ ACQUIRED_AFTER(breakpoint_lock_);
// Guards lists of classes within the class linker.
- static Mutex* classlinker_classes_lock_ ACQUIRED_AFTER(trace_lock_);
+ static ReaderWriterMutex* classlinker_classes_lock_ ACQUIRED_AFTER(trace_lock_);
// When declaring any Mutex add DEFAULT_MUTEX_ACQUIRED_AFTER to use annotalysis to check the code
// doesn't try to hold a higher level Mutex.
diff --git a/src/mem_map.cc b/src/mem_map.cc
index fb19424c48..c75dffa63c 100644
--- a/src/mem_map.cc
+++ b/src/mem_map.cc
@@ -183,4 +183,26 @@ bool MemMap::Protect(int prot) {
return false;
}
+bool MemMap::ProtectRegion(uint8_t* addr, size_t length, int prot) {
+ CHECK_GE(addr, base_begin_);
+ CHECK_LT(addr + length, reinterpret_cast<const uint8_t*>(base_begin_) + base_size_);
+
+ /*
+ * Align "addr" to a page boundary and adjust "length" appropriately.
+ * (The address must be page-aligned, the length doesn't need to be,
+ * but we do need to ensure we cover the same range.)
+ */
+ uint8_t* alignAddr = (uint8_t*) ((uintptr_t) addr & ~(kPageSize-1));
+ size_t alignLength = length + (addr - alignAddr);
+
+ if (mprotect(alignAddr, alignLength, prot) == 0) {
+ prot_ = prot;
+ return true;
+ }
+
+ PLOG(ERROR) << "mprotect(" << reinterpret_cast<void*>(alignAddr) << ", " << alignLength << ", "
+ << prot << ") failed";
+ return false;
+}
+
} // namespace art
diff --git a/src/mem_map.h b/src/mem_map.h
index 7310f78ddf..2eb7772705 100644
--- a/src/mem_map.h
+++ b/src/mem_map.h
@@ -61,6 +61,8 @@ class MemMap {
bool Protect(int prot);
+ bool ProtectRegion(uint8_t* addr, size_t length, int prot);
+
int GetProtect() const {
return prot_;
}
diff --git a/src/mirror/abstract_method-inl.h b/src/mirror/abstract_method-inl.h
index d4f0f2c6bc..a8238867aa 100644
--- a/src/mirror/abstract_method-inl.h
+++ b/src/mirror/abstract_method-inl.h
@@ -117,7 +117,8 @@ inline void AbstractMethod::AssertPcIsWithinCode(uintptr_t pc) const {
if (GetEntryPointFromCompiledCode() == GetInterpreterEntryPoint()) {
return;
}
- if (GetEntryPointFromCompiledCode() == GetResolutionTrampoline()) {
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ if (GetEntryPointFromCompiledCode() == GetResolutionTrampoline(class_linker)) {
return;
}
DCHECK(IsWithinCode(pc))
diff --git a/src/mirror/abstract_method.cc b/src/mirror/abstract_method.cc
index 5258795ace..88a9dc1aa6 100644
--- a/src/mirror/abstract_method.cc
+++ b/src/mirror/abstract_method.cc
@@ -20,7 +20,7 @@
#include "base/stringpiece.h"
#include "class-inl.h"
#include "dex_file-inl.h"
-#include "gc/card_table-inl.h"
+#include "gc/accounting/card_table-inl.h"
#include "interpreter/interpreter.h"
#include "jni_internal.h"
#include "object-inl.h"
@@ -268,45 +268,28 @@ void AbstractMethod::Invoke(Thread* self, uint32_t* args, uint32_t args_size, JV
result->SetJ(0);
}
} else {
- bool interpret = runtime->GetInstrumentation()->InterpretOnly() && !IsNative() &&
- !IsProxyMethod();
const bool kLogInvocationStartAndReturn = false;
if (GetEntryPointFromCompiledCode() != NULL) {
- if (!interpret) {
- if (kLogInvocationStartAndReturn) {
- LOG(INFO) << StringPrintf("Invoking '%s' code=%p", PrettyMethod(this).c_str(), GetEntryPointFromCompiledCode());
- }
+ if (kLogInvocationStartAndReturn) {
+ LOG(INFO) << StringPrintf("Invoking '%s' code=%p", PrettyMethod(this).c_str(), GetEntryPointFromCompiledCode());
+ }
#ifdef ART_USE_PORTABLE_COMPILER
- (*art_portable_invoke_stub)(this, args, args_size, self, result, result_type);
+ (*art_portable_invoke_stub)(this, args, args_size, self, result, result_type);
#else
- (*art_quick_invoke_stub)(this, args, args_size, self, result, result_type);
+ (*art_quick_invoke_stub)(this, args, args_size, self, result, result_type);
#endif
- if (UNLIKELY(reinterpret_cast<int32_t>(self->GetException(NULL)) == -1)) {
- // Unusual case where we were running LLVM generated code and an
- // exception was thrown to force the activations to be removed from the
- // stack. Continue execution in the interpreter.
- self->ClearException();
- ShadowFrame* shadow_frame = self->GetAndClearDeoptimizationShadowFrame(result);
- self->SetTopOfStack(NULL, 0);
- self->SetTopOfShadowStack(shadow_frame);
- interpreter::EnterInterpreterFromDeoptimize(self, shadow_frame, result);
- }
- if (kLogInvocationStartAndReturn) {
- LOG(INFO) << StringPrintf("Returned '%s' code=%p", PrettyMethod(this).c_str(), GetEntryPointFromCompiledCode());
- }
- } else {
- if (kLogInvocationStartAndReturn) {
- LOG(INFO) << "Interpreting " << PrettyMethod(this) << "'";
- }
- if (this->IsStatic()) {
- art::interpreter::EnterInterpreterFromInvoke(self, this, NULL, args, result);
- } else {
- Object* receiver = reinterpret_cast<Object*>(args[0]);
- art::interpreter::EnterInterpreterFromInvoke(self, this, receiver, args + 1, result);
- }
- if (kLogInvocationStartAndReturn) {
- LOG(INFO) << "Returned '" << PrettyMethod(this) << "'";
- }
+ if (UNLIKELY(reinterpret_cast<int32_t>(self->GetException(NULL)) == -1)) {
+ // Unusual case where we were running LLVM generated code and an
+ // exception was thrown to force the activations to be removed from the
+ // stack. Continue execution in the interpreter.
+ self->ClearException();
+ ShadowFrame* shadow_frame = self->GetAndClearDeoptimizationShadowFrame(result);
+ self->SetTopOfStack(NULL, 0);
+ self->SetTopOfShadowStack(shadow_frame);
+ interpreter::EnterInterpreterFromDeoptimize(self, shadow_frame, result);
+ }
+ if (kLogInvocationStartAndReturn) {
+ LOG(INFO) << StringPrintf("Returned '%s' code=%p", PrettyMethod(this).c_str(), GetEntryPointFromCompiledCode());
}
} else {
LOG(INFO) << "Not invoking '" << PrettyMethod(this)
diff --git a/src/mirror/abstract_method.h b/src/mirror/abstract_method.h
index c8aa11e5df..339471dd5d 100644
--- a/src/mirror/abstract_method.h
+++ b/src/mirror/abstract_method.h
@@ -18,6 +18,7 @@
#define ART_SRC_MIRROR_METHOD_H_
#include "class.h"
+#include "dex_file.h"
#include "invoke_type.h"
#include "locks.h"
#include "modifiers.h"
@@ -29,6 +30,7 @@ struct AbstractMethodOffsets;
struct ConstructorMethodOffsets;
union JValue;
struct MethodClassOffsets;
+class MethodHelper;
struct MethodOffsets;
class StringPiece;
class ShadowFrame;
@@ -37,7 +39,8 @@ namespace mirror {
class StaticStorageBase;
-typedef void (EntryPointFromInterpreter)(Thread* self, ShadowFrame* shadow_frame, JValue* result);
+typedef void (EntryPointFromInterpreter)(Thread* self, MethodHelper& mh,
+ const DexFile::CodeItem* code_item, ShadowFrame* shadow_frame, JValue* result);
// C++ mirror of java.lang.reflect.Method and java.lang.reflect.Constructor
class MANAGED AbstractMethod : public Object {
@@ -120,6 +123,14 @@ class MANAGED AbstractMethod : public Object {
bool IsProxyMethod() const;
+ bool IsPreverified() const {
+ return (GetAccessFlags() & kAccPreverified) != 0;
+ }
+
+ void SetPreverified() {
+ SetAccessFlags(GetAccessFlags() | kAccPreverified);
+ }
+
bool CheckIncompatibleClassChange(InvokeType type) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
uint16_t GetMethodIndex() const;
diff --git a/src/mirror/array.cc b/src/mirror/array.cc
index 84c2dc651a..88cd309eeb 100644
--- a/src/mirror/array.cc
+++ b/src/mirror/array.cc
@@ -20,7 +20,7 @@
#include "class-inl.h"
#include "common_throws.h"
#include "dex_file-inl.h"
-#include "gc/card_table-inl.h"
+#include "gc/accounting/card_table-inl.h"
#include "object-inl.h"
#include "object_array.h"
#include "object_array-inl.h"
@@ -51,7 +51,7 @@ Array* Array::Alloc(Thread* self, Class* array_class, int32_t component_count,
return NULL;
}
- Heap* heap = Runtime::Current()->GetHeap();
+ gc::Heap* heap = Runtime::Current()->GetHeap();
Array* array = down_cast<Array*>(heap->AllocObject(self, array_class, size));
if (array != NULL) {
DCHECK(array->IsArrayInstance());
@@ -134,14 +134,12 @@ Array* Array::CreateMultiArray(Thread* self, Class* element_class, IntArray* dim
return new_array;
}
-bool Array::ThrowArrayIndexOutOfBoundsException(int32_t index) const {
+void Array::ThrowArrayIndexOutOfBoundsException(int32_t index) const {
art::ThrowArrayIndexOutOfBoundsException(index, GetLength());
- return false;
}
-bool Array::ThrowArrayStoreException(Object* object) const {
+void Array::ThrowArrayStoreException(Object* object) const {
art::ThrowArrayStoreException(object->GetClass(), this->GetClass());
- return false;
}
template<typename T>
diff --git a/src/mirror/array.h b/src/mirror/array.h
index 33c0aeb152..98b8ea0008 100644
--- a/src/mirror/array.h
+++ b/src/mirror/array.h
@@ -73,15 +73,16 @@ class MANAGED Array : public Object {
bool IsValidIndex(int32_t index) const
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
if (UNLIKELY(index < 0 || index >= GetLength())) {
- return ThrowArrayIndexOutOfBoundsException(index);
+ ThrowArrayIndexOutOfBoundsException(index);
+ return false;
}
return true;
}
protected:
- bool ThrowArrayIndexOutOfBoundsException(int32_t index) const
+ void ThrowArrayIndexOutOfBoundsException(int32_t index) const
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- bool ThrowArrayStoreException(Object* object) const
+ void ThrowArrayStoreException(Object* object) const
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
private:
diff --git a/src/mirror/class.cc b/src/mirror/class.cc
index 15129ab6dc..2d2130c39e 100644
--- a/src/mirror/class.cc
+++ b/src/mirror/class.cc
@@ -23,7 +23,7 @@
#include "dex_cache.h"
#include "dex_file-inl.h"
#include "field-inl.h"
-#include "gc/card_table-inl.h"
+#include "gc/accounting/card_table-inl.h"
#include "object-inl.h"
#include "object_array-inl.h"
#include "object_utils.h"
@@ -604,5 +604,22 @@ Field* Class::FindField(const StringPiece& name, const StringPiece& type) {
return NULL;
}
+static void SetPreverifiedFlagOnMethods(mirror::ObjectArray<mirror::AbstractMethod>* methods)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ if (methods != NULL) {
+ for (int32_t index = 0, end = methods->GetLength(); index < end; ++index) {
+ mirror::AbstractMethod* method = methods->GetWithoutChecks(index);
+ DCHECK(method != NULL);
+ method->SetPreverified();
+ }
+ }
+}
+
+void Class::SetPreverifiedFlagOnAllMethods() {
+ DCHECK(IsVerified());
+ SetPreverifiedFlagOnMethods(GetDirectMethods());
+ SetPreverifiedFlagOnMethods(GetVirtualMethods());
+}
+
} // namespace mirror
} // namespace art
diff --git a/src/mirror/class.h b/src/mirror/class.h
index 0661b42170..084aa24c7c 100644
--- a/src/mirror/class.h
+++ b/src/mirror/class.h
@@ -235,6 +235,23 @@ class MANAGED Class : public StaticStorageBase {
return (GetAccessFlags() & kAccClassIsPhantomReference) != 0;
}
+ // Can references of this type be assigned to by things of another type? For non-array types
+ // this is a matter of whether sub-classes may exist - which they can't if the type is final.
+ // For array classes, where all the classes are final due to there being no sub-classes, an
+ // Object[] may be assigned to by a String[] but a String[] may not be assigned to by other
+ // types as the component is final.
+ bool CannotBeAssignedFromOtherTypes() const {
+ if (!IsArrayClass()) {
+ return IsFinal();
+ } else {
+ Class* component = GetComponentType();
+ if (component->IsPrimitive()) {
+ return false;
+ } else {
+ return component->CannotBeAssignedFromOtherTypes();
+ }
+ }
+ }
String* GetName() const; // Returns the cached name.
void SetName(String* name) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Sets the cached name.
@@ -726,6 +743,9 @@ class MANAGED Class : public StaticStorageBase {
static void SetClassClass(Class* java_lang_Class);
static void ResetClass();
+ // When class is verified, set the kAccPreverified flag on each method.
+ void SetPreverifiedFlagOnAllMethods() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
private:
void SetVerifyErrorClass(Class* klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/src/mirror/dex_cache-inl.h b/src/mirror/dex_cache-inl.h
new file mode 100644
index 0000000000..3b17c428a5
--- /dev/null
+++ b/src/mirror/dex_cache-inl.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_SRC_MIRROR_DEX_CACHE_INL_H_
+#define ART_SRC_MIRROR_DEX_CACHE_INL_H_
+
+#include "dex_cache.h"
+
+namespace art {
+namespace mirror {
+
+inline AbstractMethod* DexCache::GetResolvedMethod(uint32_t method_idx) const
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ AbstractMethod* method = GetResolvedMethods()->Get(method_idx);
+ // Hide resolution trampoline methods from the caller
+ if (method != NULL && method->IsRuntimeMethod()) {
+ DCHECK(method == Runtime::Current()->GetResolutionMethod());
+ return NULL;
+ } else {
+ return method;
+ }
+}
+
+} // namespace mirror
+} // namespace art
+
+#endif // ART_SRC_MIRROR_DEX_CACHE_INL_H_
diff --git a/src/mirror/dex_cache.cc b/src/mirror/dex_cache.cc
index 3009786baa..239dc5e0c3 100644
--- a/src/mirror/dex_cache.cc
+++ b/src/mirror/dex_cache.cc
@@ -19,8 +19,8 @@
#include "abstract_method-inl.h"
#include "base/logging.h"
#include "class_linker.h"
-#include "heap.h"
-#include "gc/card_table-inl.h"
+#include "gc/accounting/card_table-inl.h"
+#include "gc/heap.h"
#include "globals.h"
#include "object.h"
#include "object-inl.h"
@@ -78,17 +78,5 @@ void DexCache::Fixup(AbstractMethod* trampoline) {
}
}
-AbstractMethod* DexCache::GetResolvedMethod(uint32_t method_idx) const
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- AbstractMethod* method = GetResolvedMethods()->Get(method_idx);
- // Hide resolution trampoline methods from the caller
- if (method != NULL && method->IsRuntimeMethod()) {
- DCHECK(method == Runtime::Current()->GetResolutionMethod());
- return NULL;
- } else {
- return method;
- }
-}
-
} // namespace mirror
} // namespace art
diff --git a/src/mirror/dex_cache_test.cc b/src/mirror/dex_cache_test.cc
index 3d753e1e15..441c6da8a0 100644
--- a/src/mirror/dex_cache_test.cc
+++ b/src/mirror/dex_cache_test.cc
@@ -17,7 +17,7 @@
#include "class_linker.h"
#include "common_test.h"
#include "dex_cache.h"
-#include "heap.h"
+#include "gc/heap.h"
#include "mirror/object_array-inl.h"
#include "mirror/object-inl.h"
#include "sirt_ref.h"
diff --git a/src/mirror/field-inl.h b/src/mirror/field-inl.h
index cda461b1dc..be5dcab03d 100644
--- a/src/mirror/field-inl.h
+++ b/src/mirror/field-inl.h
@@ -20,7 +20,7 @@
#include "field.h"
#include "base/logging.h"
-#include "gc/card_table-inl.h"
+#include "gc/accounting/card_table-inl.h"
#include "jvalue.h"
#include "object-inl.h"
#include "object_utils.h"
diff --git a/src/mirror/field.cc b/src/mirror/field.cc
index 6e2559a62d..a96e8c8d54 100644
--- a/src/mirror/field.cc
+++ b/src/mirror/field.cc
@@ -17,7 +17,7 @@
#include "field.h"
#include "field-inl.h"
-#include "gc/card_table-inl.h"
+#include "gc/accounting/card_table-inl.h"
#include "object-inl.h"
#include "object_utils.h"
#include "runtime.h"
diff --git a/src/mirror/object.cc b/src/mirror/object.cc
index 4acb5679f9..b2d6e71478 100644
--- a/src/mirror/object.cc
+++ b/src/mirror/object.cc
@@ -22,8 +22,8 @@
#include "class_linker-inl.h"
#include "field.h"
#include "field-inl.h"
-#include "gc/card_table-inl.h"
-#include "heap.h"
+#include "gc/accounting/card_table-inl.h"
+#include "gc/heap.h"
#include "iftable-inl.h"
#include "monitor.h"
#include "object-inl.h"
@@ -44,7 +44,7 @@ Object* Object::Clone(Thread* self) {
// Object::SizeOf gets the right size even if we're an array.
// Using c->AllocObject() here would be wrong.
size_t num_bytes = SizeOf();
- Heap* heap = Runtime::Current()->GetHeap();
+ gc::Heap* heap = Runtime::Current()->GetHeap();
SirtRef<Object> copy(self, heap->AllocObject(self, c, num_bytes));
if (copy.get() == NULL) {
return NULL;
diff --git a/src/mirror/object_array-inl.h b/src/mirror/object_array-inl.h
index 05bce9580d..b130dac514 100644
--- a/src/mirror/object_array-inl.h
+++ b/src/mirror/object_array-inl.h
@@ -19,7 +19,7 @@
#include "object_array.h"
-#include "heap.h"
+#include "gc/heap.h"
#include "mirror/class.h"
#include "mirror/field.h"
#include "runtime.h"
@@ -101,7 +101,7 @@ inline void ObjectArray<T>::Copy(const ObjectArray<T>* src, int src_pos,
MemberOffset src_offset(DataOffset(sizeof(Object*)).Int32Value() + src_pos * sizeof(Object*));
MemberOffset dst_offset(DataOffset(sizeof(Object*)).Int32Value() + dst_pos * sizeof(Object*));
Class* array_class = dst->GetClass();
- Heap* heap = Runtime::Current()->GetHeap();
+ gc::Heap* heap = Runtime::Current()->GetHeap();
if (array_class == src->GetClass()) {
// No need for array store checks if arrays are of the same type
for (size_t i = 0; i < length; i++) {
diff --git a/src/mirror/object_test.cc b/src/mirror/object_test.cc
index abf6c2968f..53a1df95a6 100644
--- a/src/mirror/object_test.cc
+++ b/src/mirror/object_test.cc
@@ -27,8 +27,8 @@
#include "common_test.h"
#include "dex_file.h"
#include "field-inl.h"
-#include "gc/card_table-inl.h"
-#include "heap.h"
+#include "gc/accounting/card_table-inl.h"
+#include "gc/heap.h"
#include "iftable-inl.h"
#include "abstract_method-inl.h"
#include "object-inl.h"
@@ -283,7 +283,7 @@ TEST_F(ObjectTest, StaticFieldFromCode) {
uint32_t field_idx = dex_file->GetIndexForFieldId(*field_id);
Field* field = FindFieldFromCode(field_idx, clinit, Thread::Current(), StaticObjectRead,
- sizeof(Object*));
+ sizeof(Object*), true);
Object* s0 = field->GetObj(klass);
EXPECT_TRUE(s0 != NULL);
diff --git a/src/mirror/stack_trace_element.cc b/src/mirror/stack_trace_element.cc
index 9d557ec9e8..1ad01823b2 100644
--- a/src/mirror/stack_trace_element.cc
+++ b/src/mirror/stack_trace_element.cc
@@ -17,7 +17,7 @@
#include "stack_trace_element.h"
#include "class.h"
-#include "gc/card_table-inl.h"
+#include "gc/accounting/card_table-inl.h"
#include "object-inl.h"
#include "string.h"
diff --git a/src/mirror/string.cc b/src/mirror/string.cc
index 45a6779c45..97126cba4c 100644
--- a/src/mirror/string.cc
+++ b/src/mirror/string.cc
@@ -17,7 +17,7 @@
#include "string.h"
#include "array.h"
-#include "gc/card_table-inl.h"
+#include "gc/accounting/card_table-inl.h"
#include "intern_table.h"
#include "object-inl.h"
#include "runtime.h"
diff --git a/src/mirror/throwable.cc b/src/mirror/throwable.cc
index bbff9c2f82..78b76dc6ef 100644
--- a/src/mirror/throwable.cc
+++ b/src/mirror/throwable.cc
@@ -19,7 +19,7 @@
#include "abstract_method-inl.h"
#include "class-inl.h"
#include "dex_file-inl.h"
-#include "gc/card_table-inl.h"
+#include "gc/accounting/card_table-inl.h"
#include "object-inl.h"
#include "object_array.h"
#include "object_array-inl.h"
diff --git a/src/modifiers.h b/src/modifiers.h
index a15b096da2..85bc06da65 100644
--- a/src/modifiers.h
+++ b/src/modifiers.h
@@ -46,7 +46,9 @@ static const uint32_t kAccConstructor = 0x00010000; // method (dex only) <init>
static const uint32_t kAccDeclaredSynchronized = 0x00020000; // method (dex only)
static const uint32_t kAccClassIsProxy = 0x00040000; // class (dex only)
// TODO: JACK CLASS ACCESS (HACK TO BE REMOVED)
-static const uint32_t kAccClassJack = 0x000080000; // class (dex only)
+static const uint32_t kAccClassJack = 0x00080000; // class (dex only)
+
+static const uint32_t kAccPreverified = 0x00100000; // method (dex only)
// Special runtime-only flags.
// Note: if only kAccClassIsReference is set, we have a soft reference.
diff --git a/src/native/dalvik_system_DexFile.cc b/src/native/dalvik_system_DexFile.cc
index e07339cbb6..b9838f879a 100644
--- a/src/native/dalvik_system_DexFile.cc
+++ b/src/native/dalvik_system_DexFile.cc
@@ -20,7 +20,8 @@
#include "class_linker.h"
#include "common_throws.h"
#include "dex_file-inl.h"
-#include "gc/space.h"
+#include "gc/space/image_space.h"
+#include "gc/space/space-inl.h"
#include "image.h"
#include "jni_internal.h"
#include "mirror/class_loader.h"
@@ -248,13 +249,14 @@ static jboolean DexFile_isDexOptNeeded(JNIEnv* env, jclass, jstring javaFilename
return JNI_TRUE;
}
- Heap* heap = runtime->GetHeap();
- const Spaces& spaces = heap->GetSpaces();
+ gc::Heap* heap = runtime->GetHeap();
+ const std::vector<gc::space::ContinuousSpace*>& spaces = heap->GetContinuousSpaces();
// TODO: C++0x auto
- for (Spaces::const_iterator cur = spaces.begin(); cur != spaces.end(); ++cur) {
- if ((*cur)->IsImageSpace()) {
+ typedef std::vector<gc::space::ContinuousSpace*>::const_iterator It;
+ for (It it = spaces.begin(), end = spaces.end(); it != end; ++it) {
+ if ((*it)->IsImageSpace()) {
// TODO: Ensure this works with multiple image spaces.
- const ImageHeader& image_header = (*cur)->AsImageSpace()->GetImageHeader();
+ const ImageHeader& image_header = (*it)->AsImageSpace()->GetImageHeader();
if (oat_file->GetOatHeader().GetImageFileLocationOatChecksum() != image_header.GetOatChecksum()) {
ScopedObjectAccess soa(env);
LOG(INFO) << "DexFile_isDexOptNeeded cache file " << cache_location
diff --git a/src/native/dalvik_system_VMRuntime.cc b/src/native/dalvik_system_VMRuntime.cc
index d2ef43c7e2..ce3cc932a0 100644
--- a/src/native/dalvik_system_VMRuntime.cc
+++ b/src/native/dalvik_system_VMRuntime.cc
@@ -20,13 +20,14 @@
#include "common_throws.h"
#include "debugger.h"
#include "dex_file-inl.h"
+#include "gc/allocator/dlmalloc.h"
+#include "gc/space/dlmalloc_space.h"
#include "jni_internal.h"
#include "mirror/class-inl.h"
#include "mirror/object.h"
#include "mirror/object-inl.h"
#include "object_utils.h"
#include "scoped_thread_state_change.h"
-#include "gc/space.h"
#include "thread.h"
#include "thread_list.h"
#include "toStringArray.h"
@@ -125,6 +126,10 @@ static jstring VMRuntime_vmVersion(JNIEnv* env, jobject) {
return env->NewStringUTF(Runtime::Current()->GetVersion());
}
+static jstring VMRuntime_vmLibrary(JNIEnv* env, jobject) {
+ return env->NewStringUTF(kIsDebugBuild ? "libartd.so" : "libart.so");
+}
+
#if !defined(ART_USE_PORTABLE_COMPILER)
static void DisableCheckJniCallback(Thread* t, void*) {
t->GetJniEnv()->SetCheckJniEnabled(false);
@@ -164,11 +169,11 @@ static void VMRuntime_trimHeap(JNIEnv*, jobject) {
uint64_t start_ns = NanoTime();
// Trim the managed heap.
- Heap* heap = Runtime::Current()->GetHeap();
- DlMallocSpace* alloc_space = heap->GetAllocSpace();
+ gc::Heap* heap = Runtime::Current()->GetHeap();
+ gc::space::DlMallocSpace* alloc_space = heap->GetAllocSpace();
size_t alloc_space_size = alloc_space->Size();
float managed_utilization =
- static_cast<float>(alloc_space->GetNumBytesAllocated()) / alloc_space_size;
+ static_cast<float>(alloc_space->GetBytesAllocated()) / alloc_space_size;
size_t managed_reclaimed = heap->Trim();
uint64_t gc_heap_end_ns = NanoTime();
@@ -176,7 +181,7 @@ static void VMRuntime_trimHeap(JNIEnv*, jobject) {
// Trim the native heap.
dlmalloc_trim(0);
size_t native_reclaimed = 0;
- dlmalloc_inspect_all(MspaceMadviseCallback, &native_reclaimed);
+ dlmalloc_inspect_all(DlmallocMadviseCallback, &native_reclaimed);
uint64_t end_ns = NanoTime();
@@ -208,6 +213,7 @@ static JNINativeMethod gMethods[] = {
NATIVE_METHOD(VMRuntime, startJitCompilation, "()V"),
NATIVE_METHOD(VMRuntime, trimHeap, "()V"),
NATIVE_METHOD(VMRuntime, vmVersion, "()Ljava/lang/String;"),
+ NATIVE_METHOD(VMRuntime, vmLibrary, "()Ljava/lang/String;"),
};
void register_dalvik_system_VMRuntime(JNIEnv* env) {
diff --git a/src/native/java_lang_Runtime.cc b/src/native/java_lang_Runtime.cc
index 56a3a06192..e380c17793 100644
--- a/src/native/java_lang_Runtime.cc
+++ b/src/native/java_lang_Runtime.cc
@@ -18,7 +18,7 @@
#include <limits.h>
#include <unistd.h>
-#include "heap.h"
+#include "gc/heap.h"
#include "jni_internal.h"
#include "mirror/class_loader.h"
#include "runtime.h"
diff --git a/src/native/java_lang_System.cc b/src/native/java_lang_System.cc
index d8df9d9dae..2462f2fd8e 100644
--- a/src/native/java_lang_System.cc
+++ b/src/native/java_lang_System.cc
@@ -15,7 +15,7 @@
*/
#include "common_throws.h"
-#include "gc/card_table-inl.h"
+#include "gc/accounting/card_table-inl.h"
#include "jni_internal.h"
#include "mirror/array.h"
#include "mirror/class.h"
diff --git a/src/native/java_lang_Thread.cc b/src/native/java_lang_Thread.cc
index 7ccfaaa350..8ef190aa3f 100644
--- a/src/native/java_lang_Thread.cc
+++ b/src/native/java_lang_Thread.cc
@@ -74,6 +74,7 @@ static jint Thread_nativeGetStatus(JNIEnv* env, jobject java_thread, jboolean ha
case kNative: return kJavaRunnable;
case kWaitingForGcToComplete: return kJavaWaiting;
case kWaitingPerformingGc: return kJavaWaiting;
+ case kWaitingForCheckPointsToRun: return kJavaWaiting;
case kWaitingForDebuggerSend: return kJavaWaiting;
case kWaitingForDebuggerToAttach: return kJavaWaiting;
case kWaitingInMainDebuggerLoop: return kJavaWaiting;
diff --git a/src/native/sun_misc_Unsafe.cc b/src/native/sun_misc_Unsafe.cc
index abb0d5cd5c..eece81a9e8 100644
--- a/src/native/sun_misc_Unsafe.cc
+++ b/src/native/sun_misc_Unsafe.cc
@@ -15,7 +15,7 @@
*/
#include "atomic.h"
-#include "gc/card_table-inl.h"
+#include "gc/accounting/card_table-inl.h"
#include "jni_internal.h"
#include "mirror/object.h"
#include "mirror/object-inl.h"
diff --git a/src/oat.cc b/src/oat.cc
index 4eb97f5e41..e606953ed5 100644
--- a/src/oat.cc
+++ b/src/oat.cc
@@ -22,7 +22,7 @@
namespace art {
const uint8_t OatHeader::kOatMagic[] = { 'o', 'a', 't', '\n' };
-const uint8_t OatHeader::kOatVersion[] = { '0', '0', '5', '\0' };
+const uint8_t OatHeader::kOatVersion[] = { '0', '0', '6', '\0' };
OatHeader::OatHeader() {
memset(this, 0, sizeof(*this));
@@ -57,6 +57,10 @@ OatHeader::OatHeader(InstructionSet instruction_set,
UpdateChecksum(image_file_location.data(), image_file_location_size_);
executable_offset_ = 0;
+ interpreter_to_interpreter_entry_offset_ = 0;
+ interpreter_to_quick_entry_offset_ = 0;
+ portable_resolution_trampoline_offset_ = 0;
+ quick_resolution_trampoline_offset_ = 0;
}
bool OatHeader::IsValid() const {
@@ -97,6 +101,92 @@ uint32_t OatHeader::GetExecutableOffset() const {
return executable_offset_;
}
+void OatHeader::SetExecutableOffset(uint32_t executable_offset) {
+ DCHECK_ALIGNED(executable_offset, kPageSize);
+ CHECK_GT(executable_offset, sizeof(OatHeader));
+ DCHECK(IsValid());
+ DCHECK_EQ(executable_offset_, 0U);
+
+ executable_offset_ = executable_offset;
+ UpdateChecksum(&executable_offset_, sizeof(executable_offset));
+}
+
+const void* OatHeader::GetInterpreterToInterpreterEntry() const {
+ return reinterpret_cast<const uint8_t*>(this) + GetInterpreterToInterpreterEntryOffset();
+}
+
+uint32_t OatHeader::GetInterpreterToInterpreterEntryOffset() const {
+ DCHECK(IsValid());
+ CHECK_GE(interpreter_to_interpreter_entry_offset_, executable_offset_);
+ return interpreter_to_interpreter_entry_offset_;
+}
+
+void OatHeader::SetInterpreterToInterpreterEntryOffset(uint32_t offset) {
+ CHECK(offset == 0 || offset >= executable_offset_);
+ DCHECK(IsValid());
+ DCHECK_EQ(interpreter_to_interpreter_entry_offset_, 0U) << offset;
+
+ interpreter_to_interpreter_entry_offset_ = offset;
+ UpdateChecksum(&interpreter_to_interpreter_entry_offset_, sizeof(offset));
+}
+
+const void* OatHeader::GetInterpreterToQuickEntry() const {
+ return reinterpret_cast<const uint8_t*>(this) + GetInterpreterToQuickEntryOffset();
+}
+
+uint32_t OatHeader::GetInterpreterToQuickEntryOffset() const {
+ DCHECK(IsValid());
+ CHECK_GE(interpreter_to_quick_entry_offset_, interpreter_to_interpreter_entry_offset_);
+ return interpreter_to_quick_entry_offset_;
+}
+
+void OatHeader::SetInterpreterToQuickEntryOffset(uint32_t offset) {
+ CHECK(offset == 0 || offset >= interpreter_to_interpreter_entry_offset_);
+ DCHECK(IsValid());
+ DCHECK_EQ(interpreter_to_quick_entry_offset_, 0U) << offset;
+
+ interpreter_to_quick_entry_offset_ = offset;
+ UpdateChecksum(&interpreter_to_quick_entry_offset_, sizeof(offset));
+}
+
+const void* OatHeader::GetPortableResolutionTrampoline() const {
+ return reinterpret_cast<const uint8_t*>(this) + GetPortableResolutionTrampolineOffset();
+}
+
+uint32_t OatHeader::GetPortableResolutionTrampolineOffset() const {
+ DCHECK(IsValid());
+ CHECK_GE(portable_resolution_trampoline_offset_, interpreter_to_quick_entry_offset_);
+ return portable_resolution_trampoline_offset_;
+}
+
+void OatHeader::SetPortableResolutionTrampolineOffset(uint32_t offset) {
+ CHECK(offset == 0 || offset >= interpreter_to_quick_entry_offset_);
+ DCHECK(IsValid());
+ DCHECK_EQ(portable_resolution_trampoline_offset_, 0U) << offset;
+
+ portable_resolution_trampoline_offset_ = offset;
+ UpdateChecksum(&portable_resolution_trampoline_offset_, sizeof(offset));
+}
+
+const void* OatHeader::GetQuickResolutionTrampoline() const {
+ return reinterpret_cast<const uint8_t*>(this) + GetQuickResolutionTrampolineOffset();
+}
+
+uint32_t OatHeader::GetQuickResolutionTrampolineOffset() const {
+ DCHECK(IsValid());
+ CHECK_GE(quick_resolution_trampoline_offset_, portable_resolution_trampoline_offset_);
+ return quick_resolution_trampoline_offset_;
+}
+
+void OatHeader::SetQuickResolutionTrampolineOffset(uint32_t offset) {
+ CHECK(offset == 0 || offset >= portable_resolution_trampoline_offset_);
+ DCHECK(IsValid());
+ DCHECK_EQ(quick_resolution_trampoline_offset_, 0U) << offset;
+
+ quick_resolution_trampoline_offset_ = offset;
+ UpdateChecksum(&quick_resolution_trampoline_offset_, sizeof(offset));
+}
+
uint32_t OatHeader::GetImageFileLocationOatChecksum() const {
CHECK(IsValid());
return image_file_location_oat_checksum_;
@@ -123,16 +213,6 @@ std::string OatHeader::GetImageFileLocation() const {
GetImageFileLocationSize());
}
-void OatHeader::SetExecutableOffset(uint32_t executable_offset) {
- DCHECK_ALIGNED(executable_offset, kPageSize);
- CHECK_GT(executable_offset, sizeof(OatHeader));
- DCHECK(IsValid());
- DCHECK_EQ(executable_offset_, 0U);
-
- executable_offset_ = executable_offset;
- UpdateChecksum(&executable_offset_, sizeof(executable_offset));
-}
-
OatMethodOffsets::OatMethodOffsets()
: code_offset_(0),
frame_size_in_bytes_(0),
diff --git a/src/oat.h b/src/oat.h
index cf988918f0..c67a1a6630 100644
--- a/src/oat.h
+++ b/src/oat.h
@@ -43,8 +43,20 @@ class PACKED(4) OatHeader {
return dex_file_count_;
}
uint32_t GetExecutableOffset() const;
- InstructionSet GetInstructionSet() const;
void SetExecutableOffset(uint32_t executable_offset);
+ const void* GetInterpreterToInterpreterEntry() const;
+ uint32_t GetInterpreterToInterpreterEntryOffset() const;
+ void SetInterpreterToInterpreterEntryOffset(uint32_t offset);
+ const void* GetInterpreterToQuickEntry() const;
+ uint32_t GetInterpreterToQuickEntryOffset() const;
+ void SetInterpreterToQuickEntryOffset(uint32_t offset);
+ const void* GetPortableResolutionTrampoline() const;
+ uint32_t GetPortableResolutionTrampolineOffset() const;
+ void SetPortableResolutionTrampolineOffset(uint32_t offset);
+ const void* GetQuickResolutionTrampoline() const;
+ uint32_t GetQuickResolutionTrampolineOffset() const;
+ void SetQuickResolutionTrampolineOffset(uint32_t offset);
+ InstructionSet GetInstructionSet() const;
uint32_t GetImageFileLocationOatChecksum() const;
uint32_t GetImageFileLocationOatDataBegin() const;
uint32_t GetImageFileLocationSize() const;
@@ -62,6 +74,10 @@ class PACKED(4) OatHeader {
InstructionSet instruction_set_;
uint32_t dex_file_count_;
uint32_t executable_offset_;
+ uint32_t interpreter_to_interpreter_entry_offset_;
+ uint32_t interpreter_to_quick_entry_offset_;
+ uint32_t portable_resolution_trampoline_offset_;
+ uint32_t quick_resolution_trampoline_offset_;
uint32_t image_file_location_oat_checksum_;
uint32_t image_file_location_oat_data_begin_;
diff --git a/src/oat/runtime/arm/oat_support_entrypoints_arm.cc b/src/oat/runtime/arm/oat_support_entrypoints_arm.cc
index 1a5fe47e58..2e9453ce9c 100644
--- a/src/oat/runtime/arm/oat_support_entrypoints_arm.cc
+++ b/src/oat/runtime/arm/oat_support_entrypoints_arm.cc
@@ -91,12 +91,26 @@ extern "C" uint64_t art_quick_shl_long(uint64_t, uint32_t);
extern "C" uint64_t art_quick_shr_long(uint64_t, uint32_t);
extern "C" uint64_t art_quick_ushr_long(uint64_t, uint32_t);
+// Interpreter entrypoints.
+extern "C" void artInterpreterToInterpreterEntry(Thread* self, MethodHelper& mh,
+ const DexFile::CodeItem* code_item,
+ ShadowFrame* shadow_frame, JValue* result);
+extern "C" void artInterpreterToQuickEntry(Thread* self, MethodHelper& mh,
+ const DexFile::CodeItem* code_item,
+ ShadowFrame* shadow_frame, JValue* result);
+
// Intrinsic entrypoints.
extern "C" int32_t __memcmp16(void*, void*, int32_t);
extern "C" int32_t art_quick_indexof(void*, uint32_t, uint32_t, uint32_t);
extern "C" int32_t art_quick_string_compareto(void*, void*);
// Invoke entrypoints.
+extern "C" const void* artPortableResolutionTrampoline(mirror::AbstractMethod* called,
+ mirror::Object* receiver,
+ mirror::AbstractMethod** sp, Thread* thread);
+extern "C" const void* artQuickResolutionTrampoline(mirror::AbstractMethod* called,
+ mirror::Object* receiver,
+ mirror::AbstractMethod** sp, Thread* thread);
extern "C" void art_quick_invoke_direct_trampoline_with_access_check(uint32_t, void*);
extern "C" void art_quick_invoke_interface_trampoline(uint32_t, void*);
extern "C" void art_quick_invoke_interface_trampoline_with_access_check(uint32_t, void*);
@@ -187,6 +201,10 @@ void InitEntryPoints(EntryPoints* points) {
points->pShrLong = art_quick_shr_long;
points->pUshrLong = art_quick_ushr_long;
+ // Interpreter
+ points->pInterpreterToInterpreterEntry = artInterpreterToInterpreterEntry;
+ points->pInterpreterToQuickEntry = artInterpreterToQuickEntry;
+
// Intrinsics
points->pIndexOf = art_quick_indexof;
points->pMemcmp16 = __memcmp16;
@@ -194,6 +212,8 @@ void InitEntryPoints(EntryPoints* points) {
points->pMemcpy = memcpy;
// Invocation
+ points->pPortableResolutionTrampolineFromCode = artPortableResolutionTrampoline;
+ points->pQuickResolutionTrampolineFromCode = artQuickResolutionTrampoline;
points->pInvokeDirectTrampolineWithAccessCheck = art_quick_invoke_direct_trampoline_with_access_check;
points->pInvokeInterfaceTrampoline = art_quick_invoke_interface_trampoline;
points->pInvokeInterfaceTrampolineWithAccessCheck = art_quick_invoke_interface_trampoline_with_access_check;
diff --git a/src/oat/runtime/arm/runtime_support_arm.S b/src/oat/runtime/arm/runtime_support_arm.S
index 3578ba0d16..f19e8bada0 100644
--- a/src/oat/runtime/arm/runtime_support_arm.S
+++ b/src/oat/runtime/arm/runtime_support_arm.S
@@ -246,48 +246,6 @@ INVOKE_TRAMPOLINE art_quick_invoke_direct_trampoline_with_access_check, artInvok
INVOKE_TRAMPOLINE art_quick_invoke_super_trampoline_with_access_check, artInvokeSuperTrampolineWithAccessCheck
INVOKE_TRAMPOLINE art_quick_invoke_virtual_trampoline_with_access_check, artInvokeVirtualTrampolineWithAccessCheck
- /*
- * Portable resolution trampoline.
- */
- .extern artPortableResolutionTrampoline
-ENTRY art_portable_resolution_trampoline
- push {r0, r1, r2, r3, lr} @ spill regs
- .save {r0, r1, r2, r3, lr}
- .pad #20
- .cfi_adjust_cfa_offset 20
- sub sp, #12 @ pad stack pointer to align frame
- .pad #12
- .cfi_adjust_cfa_offset 12
- mov r2, r9 @ pass Thread::Current
- mov r1, sp @ pass stack pointer
- blx artPortableResolutionTrampoline @ (method_idx, sp, Thread*)
- mov r12, r0 @ save method code pointer result
- add sp, #12 @ remove padding from stack pointer
- .cfi_adjust_cfa_offset -12
- pop {r0, r1, r2, r3, lr} @ restore regs
- .cfi_adjust_cfa_offset -20
- cmp r12, #0 @ is method code null?
- bxne r12 @ if non-null, tail call to method's code
- bx lr @ otherwise, return to caller to handle exception
-END art_portable_resolution_trampoline
-
- /*
- * Quick resolution trampoline.
- */
- .extern artQuickResolutionTrampoline
-ENTRY art_quick_resolution_trampoline
- SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME @ save callee saves in case allocation triggers GC
- mov r2, r9 @ pass Thread::Current
- mov r1, sp @ pass stack pointer
- blx artQuickResolutionTrampoline @ (method_idx, sp, Thread*)
- mov r12, r0 @ save method code pointer result
- add sp, #4 @ set up stack pointer
- .cfi_adjust_cfa_offset -4
- pop {r0-r3, r5-r8, r10-r11, lr} @ 11 words, r0 will hold method*
- .cfi_adjust_cfa_offset -44
- bx r12 @ leaf call to method code
-END art_quick_resolution_trampoline
-
/*
* Portable invocation stub.
* On entry:
diff --git a/src/oat/runtime/mips/oat_support_entrypoints_mips.cc b/src/oat/runtime/mips/oat_support_entrypoints_mips.cc
index eb82c42894..8e066118cd 100644
--- a/src/oat/runtime/mips/oat_support_entrypoints_mips.cc
+++ b/src/oat/runtime/mips/oat_support_entrypoints_mips.cc
@@ -93,12 +93,26 @@ extern "C" uint64_t art_quick_shl_long(uint64_t, uint32_t);
extern "C" uint64_t art_quick_shr_long(uint64_t, uint32_t);
extern "C" uint64_t art_quick_ushr_long(uint64_t, uint32_t);
+// Interpreter entrypoints.
+extern "C" void artInterpreterToInterpreterEntry(Thread* self, MethodHelper& mh,
+ const DexFile::CodeItem* code_item,
+ ShadowFrame* shadow_frame, JValue* result);
+extern "C" void artInterpreterToQuickEntry(Thread* self, MethodHelper& mh,
+ const DexFile::CodeItem* code_item,
+ ShadowFrame* shadow_frame, JValue* result);
+
// Intrinsic entrypoints.
extern "C" int32_t __memcmp16(void*, void*, int32_t);
extern "C" int32_t art_quick_indexof(void*, uint32_t, uint32_t, uint32_t);
extern "C" int32_t art_quick_string_compareto(void*, void*);
// Invoke entrypoints.
+extern "C" const void* artPortableResolutionTrampoline(mirror::AbstractMethod* called,
+ mirror::Object* receiver,
+ mirror::AbstractMethod** sp, Thread* thread);
+extern "C" const void* artQuickResolutionTrampoline(mirror::AbstractMethod* called,
+ mirror::Object* receiver,
+ mirror::AbstractMethod** sp, Thread* thread);
extern "C" void art_quick_invoke_direct_trampoline_with_access_check(uint32_t, void*);
extern "C" void art_quick_invoke_interface_trampoline(uint32_t, void*);
extern "C" void art_quick_invoke_interface_trampoline_with_access_check(uint32_t, void*);
@@ -188,6 +202,10 @@ void InitEntryPoints(EntryPoints* points) {
points->pShrLong = art_quick_shr_long;
points->pUshrLong = art_quick_ushr_long;
+ // Interpreter
+ points->pInterpreterToInterpreterEntry = artInterpreterToInterpreterEntry;
+ points->pInterpreterToQuickEntry = artInterpreterToQuickEntry;
+
// Intrinsics
points->pIndexOf = art_quick_indexof;
points->pMemcmp16 = __memcmp16;
@@ -195,6 +213,8 @@ void InitEntryPoints(EntryPoints* points) {
points->pMemcpy = memcpy;
// Invocation
+ points->pPortableResolutionTrampolineFromCode = artPortableResolutionTrampoline;
+ points->pQuickResolutionTrampolineFromCode = artQuickResolutionTrampoline;
points->pInvokeDirectTrampolineWithAccessCheck = art_quick_invoke_direct_trampoline_with_access_check;
points->pInvokeInterfaceTrampoline = art_quick_invoke_interface_trampoline;
points->pInvokeInterfaceTrampolineWithAccessCheck = art_quick_invoke_interface_trampoline_with_access_check;
diff --git a/src/oat/runtime/mips/runtime_support_mips.S b/src/oat/runtime/mips/runtime_support_mips.S
index 2144e349ba..45d583e097 100644
--- a/src/oat/runtime/mips/runtime_support_mips.S
+++ b/src/oat/runtime/mips/runtime_support_mips.S
@@ -413,71 +413,6 @@ INVOKE_TRAMPOLINE art_quick_invoke_super_trampoline_with_access_check, artInvoke
INVOKE_TRAMPOLINE art_quick_invoke_virtual_trampoline_with_access_check, artInvokeVirtualTrampolineWithAccessCheck
/*
- * Portable resolution trampoline.
- */
- .extern artPortableResolutionTrampoline
-ENTRY art_portable_resolution_trampoline
- GENERATE_GLOBAL_POINTER
- addiu $sp, $sp, -32 # leave room for $a0, $a1, $a2, $a3, and $ra
- .cfi_adjust_cfa_offset 32
- sw $ra, 16($sp)
- .cfi_rel_offset 31, 16
- sw $a3, 12($sp)
- .cfi_rel_offset 7, 12
- sw $a2, 8($sp)
- .cfi_rel_offset 6, 8
- sw $a1, 4($sp)
- .cfi_rel_offset 5, 4
- sw $a0, 0($sp)
- .cfi_rel_offset 4, 0
- move $a2, $s1 # pass Thread::Current()
- jal artPortableResolutionTrampoline # (method_idx, sp, Thread*)
- move $a1, $sp # pass stack pointer
- lw $a0, 0($sp) # restore registers from stack
- lw $a1, 4($sp)
- lw $a2, 8($sp)
- lw $a3, 12($sp)
- lw $ra, 16($sp)
- beq $v0, $zero, resolve_fail
- addiu $sp, $sp, 32 # restore the stack
- .cfi_adjust_cfa_offset -32
- jr $t9 # leaf call to method's code
- move $t9, $v0 # put method code result in $t9
-resolve_fail:
- jr $ra
- nop
-END art_portable_resolution_trampoline
-
- /*
- * Quick resolution trampoline.
- */
- .extern artQuickResolutionTrampoline
-ENTRY art_quick_resolution_trampoline
- GENERATE_GLOBAL_POINTER
- SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
- move $a2, $s1 # pass Thread::Current()
- jal artQuickResolutionTrampoline # (method_idx, sp, Thread*)
- move $a1, $sp # pass stack pointer
- move $t9, $v0 # put method code result in $t9
- lw $a0, 0($sp) # restore registers from stack
- lw $a1, 4($sp)
- lw $a2, 8($sp)
- lw $a3, 12($sp)
- lw $s2, 28($sp)
- lw $s3, 32($sp)
- lw $s4, 36($sp)
- lw $s5, 40($sp)
- lw $s6, 44($sp)
- lw $s7, 48($sp)
- lw $gp, 52($sp)
- lw $fp, 56($sp)
- lw $ra, 60($sp)
- jr $t9 # leaf call to method's code
- addiu $sp, $sp, 64 # restore the stack
- .cfi_adjust_cfa_offset -64
-END art_quick_resolution_trampoline
-
- /*
* Common invocation stub for portable and quick.
* On entry:
* a0 = method pointer
diff --git a/src/oat/runtime/oat_support_entrypoints.h b/src/oat/runtime/oat_support_entrypoints.h
index 72d5348556..c1a2587c45 100644
--- a/src/oat/runtime/oat_support_entrypoints.h
+++ b/src/oat/runtime/oat_support_entrypoints.h
@@ -17,6 +17,7 @@
#ifndef ART_SRC_OAT_RUNTIME_OAT_SUPPORT_ENTRYPOINTS_H_
#define ART_SRC_OAT_RUNTIME_OAT_SUPPORT_ENTRYPOINTS_H_
+#include "dex_file-inl.h"
#include "runtime.h"
#define ENTRYPOINT_OFFSET(x) \
@@ -30,6 +31,8 @@ class Class;
class Object;
} // namespace mirror
class DvmDex;
+class MethodHelper;
+class ShadowFrame;
class Thread;
struct PACKED(4) EntryPoints {
@@ -104,6 +107,14 @@ struct PACKED(4) EntryPoints {
uint64_t (*pShrLong)(uint64_t, uint32_t);
uint64_t (*pUshrLong)(uint64_t, uint32_t);
+ // Interpreter
+ void (*pInterpreterToInterpreterEntry)(Thread* self, MethodHelper& mh,
+ const DexFile::CodeItem* code_item,
+ ShadowFrame* shadow_frame, JValue* result);
+ void (*pInterpreterToQuickEntry)(Thread* self, MethodHelper& mh,
+ const DexFile::CodeItem* code_item,
+ ShadowFrame* shadow_frame, JValue* result);
+
// Intrinsics
int32_t (*pIndexOf)(void*, uint32_t, uint32_t, uint32_t);
int32_t (*pMemcmp16)(void*, void*, int32_t);
@@ -111,6 +122,10 @@ struct PACKED(4) EntryPoints {
void* (*pMemcpy)(void*, const void*, size_t);
// Invocation
+ const void* (*pPortableResolutionTrampolineFromCode)(mirror::AbstractMethod*, mirror::Object*,
+ mirror::AbstractMethod**, Thread*);
+ const void* (*pQuickResolutionTrampolineFromCode)(mirror::AbstractMethod*, mirror::Object*,
+ mirror::AbstractMethod**, Thread*);
void (*pInvokeDirectTrampolineWithAccessCheck)(uint32_t, void*);
void (*pInvokeInterfaceTrampoline)(uint32_t, void*);
void (*pInvokeInterfaceTrampolineWithAccessCheck)(uint32_t, void*);
@@ -131,24 +146,25 @@ struct PACKED(4) EntryPoints {
void (*pThrowStackOverflowFromCode)(void*);
};
+
// JNI entrypoints.
extern uint32_t JniMethodStart(Thread* self)
- UNLOCK_FUNCTION(Locks::mutator_lock_) __attribute__ ((hot));
+ UNLOCK_FUNCTION(Locks::mutator_lock_) HOT_ATTR;
extern uint32_t JniMethodStartSynchronized(jobject to_lock, Thread* self)
- UNLOCK_FUNCTION(Locks::mutator_lock_) __attribute__ ((hot));
+ UNLOCK_FUNCTION(Locks::mutator_lock_) HOT_ATTR;
extern void JniMethodEnd(uint32_t saved_local_ref_cookie, Thread* self)
- SHARED_LOCK_FUNCTION(Locks::mutator_lock_) __attribute__ ((hot));
+ SHARED_LOCK_FUNCTION(Locks::mutator_lock_) HOT_ATTR;
extern void JniMethodEndSynchronized(uint32_t saved_local_ref_cookie, jobject locked,
Thread* self)
- SHARED_LOCK_FUNCTION(Locks::mutator_lock_) __attribute__ ((hot));
+ SHARED_LOCK_FUNCTION(Locks::mutator_lock_) HOT_ATTR;
extern mirror::Object* JniMethodEndWithReference(jobject result, uint32_t saved_local_ref_cookie,
Thread* self)
- SHARED_LOCK_FUNCTION(Locks::mutator_lock_) __attribute__ ((hot));
+ SHARED_LOCK_FUNCTION(Locks::mutator_lock_) HOT_ATTR;
extern mirror::Object* JniMethodEndWithReferenceSynchronized(jobject result,
uint32_t saved_local_ref_cookie,
jobject locked, Thread* self)
- SHARED_LOCK_FUNCTION(Locks::mutator_lock_) __attribute__ ((hot));
+ SHARED_LOCK_FUNCTION(Locks::mutator_lock_) HOT_ATTR;
// Initialize an entry point data structure.
void InitEntryPoints(EntryPoints* points);
diff --git a/src/oat/runtime/support_dexcache.cc b/src/oat/runtime/support_dexcache.cc
index 3e8ebc6679..0af7a6281d 100644
--- a/src/oat/runtime/support_dexcache.cc
+++ b/src/oat/runtime/support_dexcache.cc
@@ -15,7 +15,7 @@
*/
#include "callee_save_frame.h"
-#include "gc/card_table-inl.h"
+#include "gc/accounting/card_table-inl.h"
#include "class_linker-inl.h"
#include "dex_file-inl.h"
#include "mirror/abstract_method-inl.h"
diff --git a/src/oat/runtime/support_field.cc b/src/oat/runtime/support_field.cc
index 5821063cf6..c20326c63e 100644
--- a/src/oat/runtime/support_field.cc
+++ b/src/oat/runtime/support_field.cc
@@ -34,7 +34,7 @@ extern "C" uint32_t artGet32StaticFromCode(uint32_t field_idx,
return field->Get32(field->GetDeclaringClass());
}
FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- field = FindFieldFromCode(field_idx, referrer, self, StaticPrimitiveRead, sizeof(int32_t));
+ field = FindFieldFromCode(field_idx, referrer, self, StaticPrimitiveRead, sizeof(int32_t), true);
if (LIKELY(field != NULL)) {
return field->Get32(field->GetDeclaringClass());
}
@@ -50,7 +50,7 @@ extern "C" uint64_t artGet64StaticFromCode(uint32_t field_idx,
return field->Get64(field->GetDeclaringClass());
}
FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- field = FindFieldFromCode(field_idx, referrer, self, StaticPrimitiveRead, sizeof(int64_t));
+ field = FindFieldFromCode(field_idx, referrer, self, StaticPrimitiveRead, sizeof(int64_t), true);
if (LIKELY(field != NULL)) {
return field->Get64(field->GetDeclaringClass());
}
@@ -67,7 +67,7 @@ extern "C" mirror::Object* artGetObjStaticFromCode(uint32_t field_idx,
return field->GetObj(field->GetDeclaringClass());
}
FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- field = FindFieldFromCode(field_idx, referrer, self, StaticObjectRead, sizeof(mirror::Object*));
+ field = FindFieldFromCode(field_idx, referrer, self, StaticObjectRead, sizeof(mirror::Object*), true);
if (LIKELY(field != NULL)) {
return field->GetObj(field->GetDeclaringClass());
}
@@ -83,7 +83,7 @@ extern "C" uint32_t artGet32InstanceFromCode(uint32_t field_idx, mirror::Object*
return field->Get32(obj);
}
FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- field = FindFieldFromCode(field_idx, referrer, self, InstancePrimitiveRead, sizeof(int32_t));
+ field = FindFieldFromCode(field_idx, referrer, self, InstancePrimitiveRead, sizeof(int32_t), true);
if (LIKELY(field != NULL)) {
if (UNLIKELY(obj == NULL)) {
ThrowLocation throw_location = self->GetCurrentLocationForThrow();
@@ -104,7 +104,7 @@ extern "C" uint64_t artGet64InstanceFromCode(uint32_t field_idx, mirror::Object*
return field->Get64(obj);
}
FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- field = FindFieldFromCode(field_idx, referrer, self, InstancePrimitiveRead, sizeof(int64_t));
+ field = FindFieldFromCode(field_idx, referrer, self, InstancePrimitiveRead, sizeof(int64_t), true);
if (LIKELY(field != NULL)) {
if (UNLIKELY(obj == NULL)) {
ThrowLocation throw_location = self->GetCurrentLocationForThrow();
@@ -126,7 +126,7 @@ extern "C" mirror::Object* artGetObjInstanceFromCode(uint32_t field_idx, mirror:
return field->GetObj(obj);
}
FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- field = FindFieldFromCode(field_idx, referrer, self, InstanceObjectRead, sizeof(mirror::Object*));
+ field = FindFieldFromCode(field_idx, referrer, self, InstanceObjectRead, sizeof(mirror::Object*), true);
if (LIKELY(field != NULL)) {
if (UNLIKELY(obj == NULL)) {
ThrowLocation throw_location = self->GetCurrentLocationForThrow();
@@ -148,7 +148,7 @@ extern "C" int artSet32StaticFromCode(uint32_t field_idx, uint32_t new_value,
return 0; // success
}
FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- field = FindFieldFromCode(field_idx, referrer, self, StaticPrimitiveWrite, sizeof(int32_t));
+ field = FindFieldFromCode(field_idx, referrer, self, StaticPrimitiveWrite, sizeof(int32_t), true);
if (LIKELY(field != NULL)) {
field->Set32(field->GetDeclaringClass(), new_value);
return 0; // success
@@ -165,7 +165,7 @@ extern "C" int artSet64StaticFromCode(uint32_t field_idx, const mirror::Abstract
return 0; // success
}
FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- field = FindFieldFromCode(field_idx, referrer, self, StaticPrimitiveWrite, sizeof(int64_t));
+ field = FindFieldFromCode(field_idx, referrer, self, StaticPrimitiveWrite, sizeof(int64_t), true);
if (LIKELY(field != NULL)) {
field->Set64(field->GetDeclaringClass(), new_value);
return 0; // success
@@ -186,7 +186,7 @@ extern "C" int artSetObjStaticFromCode(uint32_t field_idx, mirror::Object* new_v
}
}
FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- field = FindFieldFromCode(field_idx, referrer, self, StaticObjectWrite, sizeof(mirror::Object*));
+ field = FindFieldFromCode(field_idx, referrer, self, StaticObjectWrite, sizeof(mirror::Object*), true);
if (LIKELY(field != NULL)) {
field->SetObj(field->GetDeclaringClass(), new_value);
return 0; // success
@@ -204,7 +204,7 @@ extern "C" int artSet32InstanceFromCode(uint32_t field_idx, mirror::Object* obj,
return 0; // success
}
FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- field = FindFieldFromCode(field_idx, referrer, self, InstancePrimitiveWrite, sizeof(int32_t));
+ field = FindFieldFromCode(field_idx, referrer, self, InstancePrimitiveWrite, sizeof(int32_t), true);
if (LIKELY(field != NULL)) {
if (UNLIKELY(obj == NULL)) {
ThrowLocation throw_location = self->GetCurrentLocationForThrow();
@@ -231,7 +231,7 @@ extern "C" int artSet64InstanceFromCode(uint32_t field_idx, mirror::Object* obj,
}
*sp = callee_save;
self->SetTopOfStack(sp, 0);
- field = FindFieldFromCode(field_idx, referrer, self, InstancePrimitiveWrite, sizeof(int64_t));
+ field = FindFieldFromCode(field_idx, referrer, self, InstancePrimitiveWrite, sizeof(int64_t), true);
if (LIKELY(field != NULL)) {
if (UNLIKELY(obj == NULL)) {
ThrowLocation throw_location = self->GetCurrentLocationForThrow();
@@ -257,7 +257,7 @@ extern "C" int artSetObjInstanceFromCode(uint32_t field_idx, mirror::Object* obj
}
FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
field = FindFieldFromCode(field_idx, referrer, self, InstanceObjectWrite,
- sizeof(mirror::Object*));
+ sizeof(mirror::Object*), true);
if (LIKELY(field != NULL)) {
if (UNLIKELY(obj == NULL)) {
ThrowLocation throw_location = self->GetCurrentLocationForThrow();
diff --git a/src/oat/runtime/support_interpreter.cc b/src/oat/runtime/support_interpreter.cc
index a5d6fa3c8b..55be54f2c2 100644
--- a/src/oat/runtime/support_interpreter.cc
+++ b/src/oat/runtime/support_interpreter.cc
@@ -110,12 +110,11 @@ extern "C" uint64_t artInterpreterEntry(mirror::AbstractMethod* method, Thread*
return result.GetJ();
}
-void artInterpreterToQuickEntry(Thread* self, ShadowFrame* shadow_frame, JValue* result)
+extern "C" void artInterpreterToQuickEntry(Thread* self, MethodHelper& mh,
+ const DexFile::CodeItem* code_item,
+ ShadowFrame* shadow_frame, JValue* result)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
mirror::AbstractMethod* method = shadow_frame->GetMethod();
- MethodHelper mh(method);
- const DexFile::CodeItem* code_item = mh.GetCodeItem();
-
uint16_t arg_offset = (code_item == NULL) ? 0 : code_item->registers_size_ - code_item->ins_size_;
ArgArray arg_array(mh.GetShorty(), mh.GetShortyLength());
arg_array.BuildArgArray(shadow_frame, arg_offset);
diff --git a/src/oat/runtime/support_invoke.cc b/src/oat/runtime/support_invoke.cc
index a96555d8ea..6a95f3c8ff 100644
--- a/src/oat/runtime/support_invoke.cc
+++ b/src/oat/runtime/support_invoke.cc
@@ -17,6 +17,7 @@
#include "callee_save_frame.h"
#include "dex_instruction-inl.h"
#include "mirror/class-inl.h"
+#include "mirror/dex_cache-inl.h"
#include "mirror/abstract_method-inl.h"
#include "mirror/object-inl.h"
#include "mirror/object_array-inl.h"
diff --git a/src/oat/runtime/support_stubs.cc b/src/oat/runtime/support_stubs.cc
index df2dda2174..71b67d06bb 100644
--- a/src/oat/runtime/support_stubs.cc
+++ b/src/oat/runtime/support_stubs.cc
@@ -32,6 +32,7 @@ namespace art {
// Lazily resolve a method for portable. Called by stub code.
extern "C" const void* artPortableResolutionTrampoline(mirror::AbstractMethod* called,
+ mirror::Object* receiver,
mirror::AbstractMethod** called_addr,
Thread* thread)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
@@ -79,6 +80,14 @@ extern "C" const void* artPortableResolutionTrampoline(mirror::AbstractMethod* c
invoke_type = kVirtual;
is_range = true;
break;
+ case Instruction::INVOKE_INTERFACE:
+ invoke_type = kInterface;
+ is_range = false;
+ break;
+ case Instruction::INVOKE_INTERFACE_RANGE:
+ invoke_type = kInterface;
+ is_range = true;
+ break;
default:
LOG(FATAL) << "Unexpected call into trampoline: " << instr->DumpString(NULL);
// Avoid used uninitialized warnings.
@@ -87,6 +96,12 @@ extern "C" const void* artPortableResolutionTrampoline(mirror::AbstractMethod* c
}
uint32_t dex_method_idx = (is_range) ? instr->VRegB_3rc() : instr->VRegB_35c();
called = linker->ResolveMethod(dex_method_idx, caller, invoke_type);
+ // Refine called method based on receiver.
+ if (invoke_type == kVirtual) {
+ called = receiver->GetClass()->FindVirtualMethodForVirtual(called);
+ } else if (invoke_type == kInterface) {
+ called = receiver->GetClass()->FindVirtualMethodForInterface(called);
+ }
} else {
CHECK(called->IsStatic()) << PrettyMethod(called);
invoke_type = kStatic;
@@ -129,7 +144,7 @@ extern "C" const void* artPortableResolutionTrampoline(mirror::AbstractMethod* c
// Expect class to at least be initializing.
DCHECK(called->GetDeclaringClass()->IsInitializing());
// Don't want infinite recursion.
- DCHECK(code != GetResolutionTrampoline());
+ DCHECK(code != GetResolutionTrampoline(linker));
// Set up entry into main method
*called_addr = called;
}
@@ -138,6 +153,7 @@ extern "C" const void* artPortableResolutionTrampoline(mirror::AbstractMethod* c
// Lazily resolve a method for quick. Called by stub code.
extern "C" const void* artQuickResolutionTrampoline(mirror::AbstractMethod* called,
+ mirror::Object* receiver,
mirror::AbstractMethod** sp, Thread* thread)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
#if defined(__arm__)
@@ -261,6 +277,14 @@ extern "C" const void* artQuickResolutionTrampoline(mirror::AbstractMethod* call
invoke_type = kVirtual;
is_range = true;
break;
+ case Instruction::INVOKE_INTERFACE:
+ invoke_type = kInterface;
+ is_range = false;
+ break;
+ case Instruction::INVOKE_INTERFACE_RANGE:
+ invoke_type = kInterface;
+ is_range = true;
+ break;
default:
LOG(FATAL) << "Unexpected call into trampoline: " << instr->DumpString(NULL);
// Avoid used uninitialized warnings.
@@ -334,6 +358,12 @@ extern "C" const void* artQuickResolutionTrampoline(mirror::AbstractMethod* call
if (LIKELY(!thread->IsExceptionPending())) {
// Incompatible class change should have been handled in resolve method.
CHECK(!called->CheckIncompatibleClassChange(invoke_type));
+ // Refine called method based on receiver.
+ if (invoke_type == kVirtual) {
+ called = receiver->GetClass()->FindVirtualMethodForVirtual(called);
+ } else if (invoke_type == kInterface) {
+ called = receiver->GetClass()->FindVirtualMethodForInterface(called);
+ }
// Ensure that the called method's class is initialized.
mirror::Class* called_class = called->GetDeclaringClass();
linker->EnsureInitialized(called_class, true, true);
@@ -363,7 +393,7 @@ extern "C" const void* artQuickResolutionTrampoline(mirror::AbstractMethod* call
// Expect class to at least be initializing.
DCHECK(called->GetDeclaringClass()->IsInitializing());
// Don't want infinite recursion.
- DCHECK(code != GetResolutionTrampoline());
+ DCHECK(code != GetResolutionTrampoline(linker));
// Set up entry into main method
regs[0] = reinterpret_cast<uintptr_t>(called);
}
diff --git a/src/oat/runtime/support_throw.cc b/src/oat/runtime/support_throw.cc
index b8c68a565c..9588698bb2 100644
--- a/src/oat/runtime/support_throw.cc
+++ b/src/oat/runtime/support_throw.cc
@@ -67,7 +67,7 @@ extern "C" void artThrowDivZeroFromCode(Thread* self,
mirror::AbstractMethod** sp)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
FinishCalleeSaveFrameSetup(self, sp, Runtime::kSaveAll);
- ThrowArithmeticExceptionDivideByZero(self);
+ ThrowArithmeticExceptionDivideByZero();
self->QuickDeliverException();
}
diff --git a/src/oat/runtime/x86/oat_support_entrypoints_x86.cc b/src/oat/runtime/x86/oat_support_entrypoints_x86.cc
index 357bbe0819..a90a583e9f 100644
--- a/src/oat/runtime/x86/oat_support_entrypoints_x86.cc
+++ b/src/oat/runtime/x86/oat_support_entrypoints_x86.cc
@@ -75,6 +75,14 @@ extern "C" uint64_t art_quick_lshl_from_code(uint64_t, uint32_t);
extern "C" uint64_t art_quick_lshr_from_code(uint64_t, uint32_t);
extern "C" uint64_t art_quick_lushr_from_code(uint64_t, uint32_t);
+// Interpreter entrypoints.
+extern "C" void artInterpreterToInterpreterEntry(Thread* self, MethodHelper& mh,
+ const DexFile::CodeItem* code_item,
+ ShadowFrame* shadow_frame, JValue* result);
+extern "C" void artInterpreterToQuickEntry(Thread* self, MethodHelper& mh,
+ const DexFile::CodeItem* code_item,
+ ShadowFrame* shadow_frame, JValue* result);
+
// Intrinsic entrypoints.
extern "C" int32_t art_quick_memcmp16(void*, void*, int32_t);
extern "C" int32_t art_quick_indexof(void*, uint32_t, uint32_t, uint32_t);
@@ -82,6 +90,12 @@ extern "C" int32_t art_quick_string_compareto(void*, void*);
extern "C" void* art_quick_memcpy(void*, const void*, size_t);
// Invoke entrypoints.
+extern "C" const void* artPortableResolutionTrampoline(mirror::AbstractMethod* called,
+ mirror::Object* receiver,
+ mirror::AbstractMethod** sp, Thread* thread);
+extern "C" const void* artQuickResolutionTrampoline(mirror::AbstractMethod* called,
+ mirror::Object* receiver,
+ mirror::AbstractMethod** sp, Thread* thread);
extern "C" void art_quick_invoke_direct_trampoline_with_access_check(uint32_t, void*);
extern "C" void art_quick_invoke_interface_trampoline(uint32_t, void*);
extern "C" void art_quick_invoke_interface_trampoline_with_access_check(uint32_t, void*);
@@ -171,6 +185,10 @@ void InitEntryPoints(EntryPoints* points) {
points->pShrLong = art_quick_lshr_from_code;
points->pUshrLong = art_quick_lushr_from_code;
+ // Interpreter
+ points->pInterpreterToInterpreterEntry = artInterpreterToInterpreterEntry;
+ points->pInterpreterToQuickEntry = artInterpreterToQuickEntry;
+
// Intrinsics
points->pIndexOf = art_quick_indexof;
points->pMemcmp16 = art_quick_memcmp16;
@@ -178,6 +196,8 @@ void InitEntryPoints(EntryPoints* points) {
points->pMemcpy = art_quick_memcpy;
// Invocation
+ points->pPortableResolutionTrampolineFromCode = artPortableResolutionTrampoline;
+ points->pQuickResolutionTrampolineFromCode = artQuickResolutionTrampoline;
points->pInvokeDirectTrampolineWithAccessCheck = art_quick_invoke_direct_trampoline_with_access_check;
points->pInvokeInterfaceTrampoline = art_quick_invoke_interface_trampoline;
points->pInvokeInterfaceTrampolineWithAccessCheck = art_quick_invoke_interface_trampoline_with_access_check;
diff --git a/src/oat/runtime/x86/runtime_support_x86.S b/src/oat/runtime/x86/runtime_support_x86.S
index d3a1fb73ff..ee6db0c3f8 100644
--- a/src/oat/runtime/x86/runtime_support_x86.S
+++ b/src/oat/runtime/x86/runtime_support_x86.S
@@ -301,55 +301,6 @@ INVOKE_TRAMPOLINE art_quick_invoke_direct_trampoline_with_access_check, artInvok
INVOKE_TRAMPOLINE art_quick_invoke_super_trampoline_with_access_check, artInvokeSuperTrampolineWithAccessCheck
INVOKE_TRAMPOLINE art_quick_invoke_virtual_trampoline_with_access_check, artInvokeVirtualTrampolineWithAccessCheck
- /*
- * Portable resolution trampoline.
- */
-DEFINE_FUNCTION art_portable_resolution_trampoline
- PUSH ebp // stash %ebp
- movl %esp, %ebp // save %esp
- .cfi_def_cfa_register ebp
- subl LITERAL(8), %esp // align stack
- movl 8(%ebp), %eax // load the called method* into %eax
- leal 8(%ebp), %edx // put the called method* address in %edx
- pushl %fs:THREAD_SELF_OFFSET // pass Thread::Current()
- PUSH edx // pass called method* address
- PUSH eax // pass method*
- call SYMBOL(artPortableResolutionTrampoline) // (method_idx, sp, Thread*)
- leave // restore the stack and %ebp
- .cfi_def_cfa esp, 4
- .cfi_restore ebp
- cmpl LITERAL(0), %eax // check if returned method code is null
- je resolve_fail // if null, jump to return to handle
- jmp *%eax // otherwise, tail call to intended method
-resolve_fail:
- ret
-END_FUNCTION art_portable_resolution_trampoline
-
- /*
- * Quick resolution trampoline.
- */
-DEFINE_FUNCTION art_quick_resolution_trampoline
- SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
- movl %esp, %ecx // save stack pointer
- PUSH eax // align stack
- pushl %fs:THREAD_SELF_OFFSET // pass Thread::Current()
- .cfi_adjust_cfa_offset 4
- PUSH ecx // pass stack pointer
- PUSH eax // pass method*
- call SYMBOL(artQuickResolutionTrampoline) // (method_idx, sp, Thread*)
- movl %eax, %edi // save returned code pointer in %edi
- addl LITERAL(16), %esp // pop arguments
- .cfi_adjust_cfa_offset -16
- POP eax // restore registers
- POP ecx
- POP edx
- POP ebx
- POP ebp
- POP esi
- xchgl %edi, (%esp) // swap %edi and code pointer
- ret // tail call to intended method
-END_FUNCTION art_quick_resolution_trampoline
-
/*
* Portable invocation stub.
* On entry:
diff --git a/src/oat_test.cc b/src/oat_test.cc
index dd336d9a9b..29e2891b40 100644
--- a/src/oat_test.cc
+++ b/src/oat_test.cc
@@ -68,16 +68,16 @@ TEST_F(OatTest, WriteRead) {
const bool compile = false; // DISABLED_ due to the time to compile libcore
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- jobject class_loader = NULL;
- if (compile) {
- // TODO: make selectable
+ // TODO: make selectable
#if defined(ART_USE_PORTABLE_COMPILER)
- CompilerBackend compiler_backend = kPortable;
+ CompilerBackend compiler_backend = kPortable;
#else
- CompilerBackend compiler_backend = kQuick;
+ CompilerBackend compiler_backend = kQuick;
#endif
- compiler_driver_.reset(new CompilerDriver(compiler_backend, kThumb2, false, 2, false,
- NULL, true, true));
+ compiler_driver_.reset(new CompilerDriver(compiler_backend, kThumb2, false, NULL, 2, false,
+ true, true));
+ jobject class_loader = NULL;
+ if (compile) {
compiler_driver_->CompileAll(class_loader, class_linker->GetBootClassPath());
}
@@ -143,7 +143,7 @@ TEST_F(OatTest, WriteRead) {
TEST_F(OatTest, OatHeaderSizeCheck) {
// If this test is failing and you have to update these constants,
// it is time to update OatHeader::kOatVersion
- EXPECT_EQ(36U, sizeof(OatHeader));
+ EXPECT_EQ(52U, sizeof(OatHeader));
EXPECT_EQ(28U, sizeof(OatMethodOffsets));
}
diff --git a/src/oat_writer.cc b/src/oat_writer.cc
index 8acbfe9ca5..1d249d674f 100644
--- a/src/oat_writer.cc
+++ b/src/oat_writer.cc
@@ -22,6 +22,7 @@
#include "base/unix_file/fd_file.h"
#include "class_linker.h"
#include "dex_file-inl.h"
+#include "gc/space/space.h"
#include "mirror/abstract_method-inl.h"
#include "mirror/array.h"
#include "mirror/class_loader.h"
@@ -30,7 +31,6 @@
#include "output_stream.h"
#include "safe_map.h"
#include "scoped_thread_state_change.h"
-#include "gc/space.h"
#include "verifier/method_verifier.h"
namespace art {
@@ -54,13 +54,35 @@ OatWriter::OatWriter(const std::vector<const DexFile*>& dex_files,
uint32_t image_file_location_oat_begin,
const std::string& image_file_location,
const CompilerDriver* compiler)
- : compiler_driver_(compiler) {
- image_file_location_oat_checksum_ = image_file_location_oat_checksum;
- image_file_location_oat_begin_ = image_file_location_oat_begin;
- image_file_location_ = image_file_location;
- dex_files_ = &dex_files;
- oat_header_ = NULL;
- executable_offset_padding_length_ = 0;
+ : compiler_driver_(compiler),
+ dex_files_(&dex_files),
+ image_file_location_oat_checksum_(image_file_location_oat_checksum),
+ image_file_location_oat_begin_(image_file_location_oat_begin),
+ image_file_location_(image_file_location),
+ oat_header_(NULL),
+ size_dex_file_alignment_(0),
+ size_executable_offset_alignment_(0),
+ size_oat_header_(0),
+ size_oat_header_image_file_location_(0),
+ size_dex_file_(0),
+ size_interpreter_to_interpreter_entry_(0),
+ size_interpreter_to_quick_entry_(0),
+ size_portable_resolution_trampoline_(0),
+ size_quick_resolution_trampoline_(0),
+ size_stubs_alignment_(0),
+ size_code_size_(0),
+ size_code_(0),
+ size_code_alignment_(0),
+ size_mapping_table_(0),
+ size_vmap_table_(0),
+ size_gc_map_(0),
+ size_oat_dex_file_location_size_(0),
+ size_oat_dex_file_location_data_(0),
+ size_oat_dex_file_location_checksum_(0),
+ size_oat_dex_file_offset_(0),
+ size_oat_dex_file_methods_offsets_(0),
+ size_oat_class_status_(0),
+ size_oat_class_method_offsets_(0) {
size_t offset = InitOatHeader();
offset = InitOatDexFiles(offset);
@@ -70,6 +92,7 @@ OatWriter::OatWriter(const std::vector<const DexFile*>& dex_files,
offset = InitOatCodeDexFiles(offset);
CHECK_EQ(dex_files_->size(), oat_dex_files_.size());
+ CHECK(image_file_location.empty() == compiler->IsImage());
}
OatWriter::~OatWriter() {
@@ -106,7 +129,9 @@ size_t OatWriter::InitDexFiles(size_t offset) {
// calculate the offsets within OatDexFiles to the DexFiles
for (size_t i = 0; i != dex_files_->size(); ++i) {
// dex files are required to be 4 byte aligned
+ size_t original_offset = offset;
offset = RoundUp(offset, 4);
+ size_dex_file_alignment_ += offset - original_offset;
// set offset in OatDexFile to DexFile
oat_dex_files_[i]->dex_file_offset_ = offset;
@@ -162,7 +187,33 @@ size_t OatWriter::InitOatCode(size_t offset) {
// required to be on a new page boundary
offset = RoundUp(offset, kPageSize);
oat_header_->SetExecutableOffset(offset);
- executable_offset_padding_length_ = offset - old_offset;
+ size_executable_offset_alignment_ = offset - old_offset;
+ if (compiler_driver_->IsImage()) {
+ InstructionSet instruction_set = compiler_driver_->GetInstructionSet();
+ oat_header_->SetInterpreterToInterpreterEntryOffset(offset);
+ interpreter_to_interpreter_entry_.reset(compiler_driver_->CreateInterpreterToInterpreterEntry());
+ offset += interpreter_to_interpreter_entry_->size();
+
+ offset = CompiledCode::AlignCode(offset, instruction_set);
+ oat_header_->SetInterpreterToQuickEntryOffset(offset);
+ interpreter_to_quick_entry_.reset(compiler_driver_->CreateInterpreterToQuickEntry());
+ offset += interpreter_to_quick_entry_->size();
+
+ offset = CompiledCode::AlignCode(offset, instruction_set);
+ oat_header_->SetPortableResolutionTrampolineOffset(offset);
+ portable_resolution_trampoline_.reset(compiler_driver_->CreatePortableResolutionTrampoline());
+ offset += portable_resolution_trampoline_->size();
+
+ offset = CompiledCode::AlignCode(offset, instruction_set);
+ oat_header_->SetQuickResolutionTrampolineOffset(offset);
+ quick_resolution_trampoline_.reset(compiler_driver_->CreateQuickResolutionTrampoline());
+ offset += quick_resolution_trampoline_->size();
+ } else {
+ oat_header_->SetInterpreterToInterpreterEntryOffset(0);
+ oat_header_->SetInterpreterToQuickEntryOffset(0);
+ oat_header_->SetPortableResolutionTrampolineOffset(0);
+ oat_header_->SetQuickResolutionTrampolineOffset(0);
+ }
return offset;
}
@@ -389,11 +440,13 @@ bool OatWriter::Write(OutputStream& out) {
PLOG(ERROR) << "Failed to write oat header to " << out.GetLocation();
return false;
}
+ size_oat_header_ += sizeof(*oat_header_);
if (!out.WriteFully(image_file_location_.data(), image_file_location_.size())) {
PLOG(ERROR) << "Failed to write oat header image file location to " << out.GetLocation();
return false;
}
+ size_oat_header_image_file_location_ += image_file_location_.size();
if (!WriteTables(out)) {
LOG(ERROR) << "Failed to write oat tables to " << out.GetLocation();
@@ -412,12 +465,47 @@ bool OatWriter::Write(OutputStream& out) {
return false;
}
+ if (kIsDebugBuild) {
+ uint32_t size_total = 0;
+ #define DO_STAT(x) \
+ LOG(INFO) << #x "=" << PrettySize(x) << " (" << x << "B)"; \
+ size_total += x;
+
+ DO_STAT(size_dex_file_alignment_);
+ DO_STAT(size_executable_offset_alignment_);
+ DO_STAT(size_oat_header_);
+ DO_STAT(size_oat_header_image_file_location_);
+ DO_STAT(size_dex_file_);
+ DO_STAT(size_interpreter_to_interpreter_entry_);
+ DO_STAT(size_interpreter_to_quick_entry_);
+ DO_STAT(size_portable_resolution_trampoline_);
+ DO_STAT(size_quick_resolution_trampoline_);
+ DO_STAT(size_stubs_alignment_);
+ DO_STAT(size_code_size_);
+ DO_STAT(size_code_);
+ DO_STAT(size_code_alignment_);
+ DO_STAT(size_mapping_table_);
+ DO_STAT(size_vmap_table_);
+ DO_STAT(size_gc_map_);
+ DO_STAT(size_oat_dex_file_location_size_);
+ DO_STAT(size_oat_dex_file_location_data_);
+ DO_STAT(size_oat_dex_file_location_checksum_);
+ DO_STAT(size_oat_dex_file_offset_);
+ DO_STAT(size_oat_dex_file_methods_offsets_);
+ DO_STAT(size_oat_class_status_);
+ DO_STAT(size_oat_class_method_offsets_);
+ #undef DO_STAT
+
+ LOG(INFO) << "size_total=" << PrettySize(size_total) << " (" << size_total << "B)"; \
+ CHECK_EQ(size_total, static_cast<uint32_t>(out.Seek(0, kSeekCurrent)));
+ }
+
return true;
}
bool OatWriter::WriteTables(OutputStream& out) {
for (size_t i = 0; i != oat_dex_files_.size(); ++i) {
- if (!oat_dex_files_[i]->Write(out)) {
+ if (!oat_dex_files_[i]->Write(this, out)) {
PLOG(ERROR) << "Failed to write oat dex information to " << out.GetLocation();
return false;
}
@@ -436,9 +524,10 @@ bool OatWriter::WriteTables(OutputStream& out) {
PLOG(ERROR) << "Failed to write dex file " << dex_file->GetLocation() << " to " << out.GetLocation();
return false;
}
+ size_dex_file_ += dex_file->GetHeader().file_size_;
}
for (size_t i = 0; i != oat_classes_.size(); ++i) {
- if (!oat_classes_[i]->Write(out)) {
+ if (!oat_classes_[i]->Write(this, out)) {
PLOG(ERROR) << "Failed to write oat methods information to " << out.GetLocation();
return false;
}
@@ -448,13 +537,59 @@ bool OatWriter::WriteTables(OutputStream& out) {
size_t OatWriter::WriteCode(OutputStream& out) {
uint32_t offset = oat_header_->GetExecutableOffset();
- off_t new_offset = out.Seek(executable_offset_padding_length_, kSeekCurrent);
+ off_t new_offset = out.Seek(size_executable_offset_alignment_, kSeekCurrent);
if (static_cast<uint32_t>(new_offset) != offset) {
PLOG(ERROR) << "Failed to seek to oat code section. Actual: " << new_offset
<< " Expected: " << offset << " File: " << out.GetLocation();
return 0;
}
DCHECK_OFFSET();
+ if (compiler_driver_->IsImage()) {
+ InstructionSet instruction_set = compiler_driver_->GetInstructionSet();
+ if (!out.WriteFully(&(*interpreter_to_interpreter_entry_)[0], interpreter_to_interpreter_entry_->size())) {
+ PLOG(ERROR) << "Failed to write interpreter to interpreter entry to " << out.GetLocation();
+ return false;
+ }
+ size_interpreter_to_interpreter_entry_ += interpreter_to_interpreter_entry_->size();
+ offset += interpreter_to_interpreter_entry_->size();
+ DCHECK_OFFSET();
+
+ uint32_t aligned_offset = CompiledCode::AlignCode(offset, instruction_set);
+ uint32_t alignment_padding = aligned_offset - offset;
+ out.Seek(alignment_padding, kSeekCurrent);
+ size_stubs_alignment_ += alignment_padding;
+ if (!out.WriteFully(&(*interpreter_to_quick_entry_)[0], interpreter_to_quick_entry_->size())) {
+ PLOG(ERROR) << "Failed to write interpreter to quick entry to " << out.GetLocation();
+ return false;
+ }
+ size_interpreter_to_quick_entry_ += interpreter_to_quick_entry_->size();
+ offset += alignment_padding + interpreter_to_quick_entry_->size();
+ DCHECK_OFFSET();
+
+ aligned_offset = CompiledCode::AlignCode(offset, instruction_set);
+ alignment_padding = aligned_offset - offset;
+ out.Seek(alignment_padding, kSeekCurrent);
+ size_stubs_alignment_ += alignment_padding;
+ if (!out.WriteFully(&(*portable_resolution_trampoline_)[0], portable_resolution_trampoline_->size())) {
+ PLOG(ERROR) << "Failed to write portable resolution trampoline to " << out.GetLocation();
+ return false;
+ }
+ size_portable_resolution_trampoline_ += portable_resolution_trampoline_->size();
+ offset += alignment_padding + portable_resolution_trampoline_->size();
+ DCHECK_OFFSET();
+
+ aligned_offset = CompiledCode::AlignCode(offset, instruction_set);
+ alignment_padding = aligned_offset - offset;
+ out.Seek(alignment_padding, kSeekCurrent);
+ size_stubs_alignment_ += alignment_padding;
+ if (!out.WriteFully(&(*quick_resolution_trampoline_)[0], quick_resolution_trampoline_->size())) {
+ PLOG(ERROR) << "Failed to write quick resolution trampoline to " << out.GetLocation();
+ return false;
+ }
+ size_quick_resolution_trampoline_ += quick_resolution_trampoline_->size();
+ offset += alignment_padding + quick_resolution_trampoline_->size();
+ DCHECK_OFFSET();
+ }
return offset;
}
@@ -547,6 +682,7 @@ size_t OatWriter::WriteCodeMethod(OutputStream& out, size_t offset, size_t oat_c
uint32_t aligned_code_delta = aligned_offset - offset;
if (aligned_code_delta != 0) {
off_t new_offset = out.Seek(aligned_code_delta, kSeekCurrent);
+ size_code_alignment_ += aligned_code_delta;
if (static_cast<uint32_t>(new_offset) != aligned_offset) {
PLOG(ERROR) << "Failed to seek to align oat code. Actual: " << new_offset
<< " Expected: " << aligned_offset << " File: " << out.GetLocation();
@@ -572,12 +708,14 @@ size_t OatWriter::WriteCodeMethod(OutputStream& out, size_t offset, size_t oat_c
ReportWriteFailure("method code size", method_idx, dex_file, out);
return 0;
}
+ size_code_size_ += sizeof(code_size);
offset += sizeof(code_size);
DCHECK_OFFSET();
if (!out.WriteFully(&code[0], code_size)) {
ReportWriteFailure("method code", method_idx, dex_file, out);
return 0;
}
+ size_code_ += code_size;
offset += code_size;
}
DCHECK_OFFSET();
@@ -602,6 +740,7 @@ size_t OatWriter::WriteCodeMethod(OutputStream& out, size_t offset, size_t oat_c
ReportWriteFailure("mapping table", method_idx, dex_file, out);
return 0;
}
+ size_mapping_table_ += mapping_table_size;
offset += mapping_table_size;
}
DCHECK_OFFSET();
@@ -625,6 +764,7 @@ size_t OatWriter::WriteCodeMethod(OutputStream& out, size_t offset, size_t oat_c
ReportWriteFailure("vmap table", method_idx, dex_file, out);
return 0;
}
+ size_vmap_table_ += vmap_table_size;
offset += vmap_table_size;
}
DCHECK_OFFSET();
@@ -648,6 +788,7 @@ size_t OatWriter::WriteCodeMethod(OutputStream& out, size_t offset, size_t oat_c
ReportWriteFailure("GC map", method_idx, dex_file, out);
return 0;
}
+ size_gc_map_ += gc_map_size;
offset += gc_map_size;
}
DCHECK_OFFSET();
@@ -683,29 +824,35 @@ void OatWriter::OatDexFile::UpdateChecksum(OatHeader& oat_header) const {
sizeof(methods_offsets_[0]) * methods_offsets_.size());
}
-bool OatWriter::OatDexFile::Write(OutputStream& out) const {
+bool OatWriter::OatDexFile::Write(OatWriter* oat_writer, OutputStream& out) const {
DCHECK_OFFSET_();
if (!out.WriteFully(&dex_file_location_size_, sizeof(dex_file_location_size_))) {
PLOG(ERROR) << "Failed to write dex file location length to " << out.GetLocation();
return false;
}
+ oat_writer->size_oat_dex_file_location_size_ += sizeof(dex_file_location_size_);
if (!out.WriteFully(dex_file_location_data_, dex_file_location_size_)) {
PLOG(ERROR) << "Failed to write dex file location data to " << out.GetLocation();
return false;
}
+ oat_writer->size_oat_dex_file_location_data_ += dex_file_location_size_;
if (!out.WriteFully(&dex_file_location_checksum_, sizeof(dex_file_location_checksum_))) {
PLOG(ERROR) << "Failed to write dex file location checksum to " << out.GetLocation();
return false;
}
+ oat_writer->size_oat_dex_file_location_checksum_ += sizeof(dex_file_location_checksum_);
if (!out.WriteFully(&dex_file_offset_, sizeof(dex_file_offset_))) {
PLOG(ERROR) << "Failed to write dex file offset to " << out.GetLocation();
return false;
}
+ oat_writer->size_oat_dex_file_offset_ += sizeof(dex_file_offset_);
if (!out.WriteFully(&methods_offsets_[0],
sizeof(methods_offsets_[0]) * methods_offsets_.size())) {
PLOG(ERROR) << "Failed to write methods offsets to " << out.GetLocation();
return false;
}
+ oat_writer->size_oat_dex_file_methods_offsets_ +=
+ sizeof(methods_offsets_[0]) * methods_offsets_.size();
return true;
}
@@ -736,12 +883,13 @@ void OatWriter::OatClass::UpdateChecksum(OatHeader& oat_header) const {
sizeof(method_offsets_[0]) * method_offsets_.size());
}
-bool OatWriter::OatClass::Write(OutputStream& out) const {
+bool OatWriter::OatClass::Write(OatWriter* oat_writer, OutputStream& out) const {
DCHECK_OFFSET_();
if (!out.WriteFully(&status_, sizeof(status_))) {
PLOG(ERROR) << "Failed to write class status to " << out.GetLocation();
return false;
}
+ oat_writer->size_oat_class_status_ += sizeof(status_);
DCHECK_EQ(static_cast<off_t>(GetOatMethodOffsetsOffsetFromOatHeader(0)),
out.Seek(0, kSeekCurrent));
if (!out.WriteFully(&method_offsets_[0],
@@ -749,6 +897,7 @@ bool OatWriter::OatClass::Write(OutputStream& out) const {
PLOG(ERROR) << "Failed to write method offsets to " << out.GetLocation();
return false;
}
+ oat_writer->size_oat_class_method_offsets_ += sizeof(method_offsets_[0]) * method_offsets_.size();
DCHECK_EQ(static_cast<off_t>(GetOatMethodOffsetsOffsetFromOatHeader(method_offsets_.size())),
out.Seek(0, kSeekCurrent));
return true;
diff --git a/src/oat_writer.h b/src/oat_writer.h
index e1d76f459f..b201d6b4ee 100644
--- a/src/oat_writer.h
+++ b/src/oat_writer.h
@@ -83,7 +83,8 @@ class OatWriter {
size_t InitOatDexFiles(size_t offset);
size_t InitDexFiles(size_t offset);
size_t InitOatClasses(size_t offset);
- size_t InitOatCode(size_t offset);
+ size_t InitOatCode(size_t offset)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
size_t InitOatCodeDexFiles(size_t offset)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
size_t InitOatCodeDexFile(size_t offset,
@@ -120,7 +121,7 @@ class OatWriter {
explicit OatDexFile(size_t offset, const DexFile& dex_file);
size_t SizeOf() const;
void UpdateChecksum(OatHeader& oat_header) const;
- bool Write(OutputStream& out) const;
+ bool Write(OatWriter* oat_writer, OutputStream& out) const;
// Offset of start of OatDexFile from beginning of OatHeader. It is
// used to validate file position when writing.
@@ -144,7 +145,7 @@ class OatWriter {
size_t GetOatMethodOffsetsOffsetFromOatClass(size_t class_def_method_index_) const;
size_t SizeOf() const;
void UpdateChecksum(OatHeader& oat_header) const;
- bool Write(OutputStream& out) const;
+ bool Write(OatWriter* oat_writer, OutputStream& out) const;
// Offset of start of OatClass from beginning of OatHeader. It is
// used to validate file position when writing. For Portable, it
@@ -175,7 +176,35 @@ class OatWriter {
OatHeader* oat_header_;
std::vector<OatDexFile*> oat_dex_files_;
std::vector<OatClass*> oat_classes_;
- uint32_t executable_offset_padding_length_;
+ UniquePtr<const std::vector<uint8_t> > interpreter_to_interpreter_entry_;
+ UniquePtr<const std::vector<uint8_t> > interpreter_to_quick_entry_;
+ UniquePtr<const std::vector<uint8_t> > portable_resolution_trampoline_;
+ UniquePtr<const std::vector<uint8_t> > quick_resolution_trampoline_;
+
+ // output stats
+ uint32_t size_dex_file_alignment_;
+ uint32_t size_executable_offset_alignment_;
+ uint32_t size_oat_header_;
+ uint32_t size_oat_header_image_file_location_;
+ uint32_t size_dex_file_;
+ uint32_t size_interpreter_to_interpreter_entry_;
+ uint32_t size_interpreter_to_quick_entry_;
+ uint32_t size_portable_resolution_trampoline_;
+ uint32_t size_quick_resolution_trampoline_;
+ uint32_t size_stubs_alignment_;
+ uint32_t size_code_size_;
+ uint32_t size_code_;
+ uint32_t size_code_alignment_;
+ uint32_t size_mapping_table_;
+ uint32_t size_vmap_table_;
+ uint32_t size_gc_map_;
+ uint32_t size_oat_dex_file_location_size_;
+ uint32_t size_oat_dex_file_location_data_;
+ uint32_t size_oat_dex_file_location_checksum_;
+ uint32_t size_oat_dex_file_offset_;
+ uint32_t size_oat_dex_file_methods_offsets_;
+ uint32_t size_oat_class_status_;
+ uint32_t size_oat_class_method_offsets_;
template <class T> struct MapCompare {
public:
diff --git a/src/oatdump.cc b/src/oatdump.cc
index 7a99f8dc0e..f9caa9d127 100644
--- a/src/oatdump.cc
+++ b/src/oatdump.cc
@@ -30,8 +30,9 @@
#include "dex_instruction.h"
#include "disassembler.h"
#include "gc_map.h"
-#include "gc/large_object_space.h"
-#include "gc/space.h"
+#include "gc/space/image_space.h"
+#include "gc/space/large_object_space.h"
+#include "gc/space/space-inl.h"
#include "image.h"
#include "indenter.h"
#include "mirror/abstract_method-inl.h"
@@ -679,7 +680,7 @@ class OatDumper {
class ImageDumper {
public:
explicit ImageDumper(std::ostream* os, const std::string& image_filename,
- const std::string& host_prefix, Space& image_space,
+ const std::string& host_prefix, gc::space::ImageSpace& image_space,
const ImageHeader& image_header)
: os_(os), image_filename_(image_filename), host_prefix_(host_prefix),
image_space_(image_space), image_header_(image_header) {}
@@ -763,8 +764,8 @@ class ImageDumper {
os << "OBJECTS:\n" << std::flush;
// Loop through all the image spaces and dump their objects.
- Heap* heap = Runtime::Current()->GetHeap();
- const Spaces& spaces = heap->GetSpaces();
+ gc::Heap* heap = Runtime::Current()->GetHeap();
+ const std::vector<gc::space::ContinuousSpace*>& spaces = heap->GetContinuousSpaces();
Thread* self = Thread::Current();
{
WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
@@ -777,10 +778,11 @@ class ImageDumper {
os_ = &indent_os;
ReaderMutexLock mu(self, *Locks::heap_bitmap_lock_);
// TODO: C++0x auto
- for (Spaces::const_iterator it = spaces.begin(); it != spaces.end(); ++it) {
- Space* space = *it;
+ typedef std::vector<gc::space::ContinuousSpace*>::const_iterator It;
+ for (It it = spaces.begin(), end = spaces.end(); it != end; ++it) {
+ gc::space::Space* space = *it;
if (space->IsImageSpace()) {
- ImageSpace* image_space = space->AsImageSpace();
+ gc::space::ImageSpace* image_space = space->AsImageSpace();
image_space->GetLiveBitmap()->Walk(ImageDumper::Callback, this);
indent_os << "\n";
}
@@ -853,7 +855,13 @@ class ImageDumper {
if (value == NULL) {
os << StringPrintf("null %s\n", PrettyDescriptor(descriptor).c_str());
} else {
- PrettyObjectValue(os, fh.GetType(), value);
+ // Grab the field type without causing resolution.
+ mirror::Class* field_type = fh.GetType(false);
+ if (field_type != NULL) {
+ PrettyObjectValue(os, field_type, value);
+ } else {
+ os << StringPrintf("%p %s\n", value, PrettyDescriptor(descriptor).c_str());
+ }
}
}
}
@@ -880,7 +888,7 @@ class ImageDumper {
const void* GetOatCodeBegin(mirror::AbstractMethod* m)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
const void* code = m->GetEntryPointFromCompiledCode();
- if (code == GetResolutionTrampoline()) {
+ if (code == GetResolutionTrampoline(Runtime::Current()->GetClassLinker())) {
code = oat_dumper_->GetOatCode(m);
}
if (oat_dumper_->GetInstructionSet() == kThumb2) {
@@ -1337,7 +1345,7 @@ class ImageDumper {
std::ostream* os_;
const std::string image_filename_;
const std::string host_prefix_;
- Space& image_space_;
+ gc::space::ImageSpace& image_space_;
const ImageHeader& image_header_;
DISALLOW_COPY_AND_ASSIGN(ImageDumper);
@@ -1448,8 +1456,8 @@ static int oatdump(int argc, char** argv) {
Thread::Current()->TransitionFromRunnableToSuspended(kNative);
ScopedObjectAccess soa(Thread::Current());
- Heap* heap = Runtime::Current()->GetHeap();
- ImageSpace* image_space = heap->GetImageSpace();
+ gc::Heap* heap = Runtime::Current()->GetHeap();
+ gc::space::ImageSpace* image_space = heap->GetImageSpace();
CHECK(image_space != NULL);
const ImageHeader& image_header = image_space->GetImageHeader();
if (!image_header.IsValid()) {
diff --git a/src/object_utils.h b/src/object_utils.h
index 6c6f60b6c3..6a0742557d 100644
--- a/src/object_utils.h
+++ b/src/object_utils.h
@@ -282,13 +282,13 @@ class FieldHelper {
return field_index == 0 ? "interfaces" : "throws";
}
}
- mirror::Class* GetType() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ mirror::Class* GetType(bool resolve = true) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
uint32_t field_index = field_->GetDexFieldIndex();
if (!field_->GetDeclaringClass()->IsProxyClass()) {
const DexFile& dex_file = GetDexFile();
const DexFile::FieldId& field_id = dex_file.GetFieldId(field_index);
mirror::Class* type = GetDexCache()->GetResolvedType(field_id.type_idx_);
- if (type == NULL) {
+ if (resolve && (type == NULL)) {
type = GetClassLinker()->ResolveType(field_id.type_idx_, field_);
CHECK(type != NULL || Thread::Current()->IsExceptionPending());
}
diff --git a/src/output_stream_test.cc b/src/output_stream_test.cc
index 0e02825ff8..c9e0edefcd 100644
--- a/src/output_stream_test.cc
+++ b/src/output_stream_test.cc
@@ -25,7 +25,7 @@ class OutputStreamTest : public CommonTest {
protected:
void CheckOffset(off_t expected) {
off_t actual = output_stream_->Seek(0, kSeekCurrent);
- CHECK_EQ(expected, actual);
+ EXPECT_EQ(expected, actual);
}
void SetOutputStream(OutputStream& output_stream) {
@@ -33,16 +33,16 @@ class OutputStreamTest : public CommonTest {
}
void GenerateTestOutput() {
- CHECK_EQ(3, output_stream_->Seek(3, kSeekCurrent));
+ EXPECT_EQ(3, output_stream_->Seek(3, kSeekCurrent));
CheckOffset(3);
- CHECK_EQ(2, output_stream_->Seek(2, kSeekSet));
+ EXPECT_EQ(2, output_stream_->Seek(2, kSeekSet));
CheckOffset(2);
uint8_t buf[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
- CHECK(output_stream_->WriteFully(buf, 2));
+ EXPECT_TRUE(output_stream_->WriteFully(buf, 2));
CheckOffset(4);
- CHECK_EQ(6, output_stream_->Seek(2, kSeekEnd));
+ EXPECT_EQ(6, output_stream_->Seek(2, kSeekEnd));
CheckOffset(6);
- CHECK(output_stream_->WriteFully(buf, 4));
+ EXPECT_TRUE(output_stream_->WriteFully(buf, 4));
CheckOffset(10);
}
@@ -50,8 +50,8 @@ class OutputStreamTest : public CommonTest {
uint8_t expected[] = {
0, 0, 1, 2, 0, 0, 1, 2, 3, 4
};
- CHECK_EQ(sizeof(expected), actual.size());
- CHECK_EQ(0, memcmp(expected, &actual[0], actual.size()));
+ EXPECT_EQ(sizeof(expected), actual.size());
+ EXPECT_EQ(0, memcmp(expected, &actual[0], actual.size()));
}
OutputStream* output_stream_;
@@ -63,10 +63,10 @@ TEST_F(OutputStreamTest, File) {
SetOutputStream(output_stream);
GenerateTestOutput();
UniquePtr<File> in(OS::OpenFile(tmp.GetFilename().c_str(), false));
- CHECK(in.get() != NULL);
+ EXPECT_TRUE(in.get() != NULL);
std::vector<uint8_t> actual(in->GetLength());
bool readSuccess = in->ReadFully(&actual[0], actual.size());
- CHECK(readSuccess);
+ EXPECT_TRUE(readSuccess);
CheckTestOutput(actual);
}
diff --git a/src/runtime.cc b/src/runtime.cc
index 2fc104ad8e..3a528a125e 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -34,8 +34,9 @@
#include "constants_mips.h"
#include "constants_x86.h"
#include "debugger.h"
-#include "gc/card_table-inl.h"
-#include "heap.h"
+#include "gc/accounting/card_table-inl.h"
+#include "gc/heap.h"
+#include "gc/space/space.h"
#include "image.h"
#include "instrumentation.h"
#include "intern_table.h"
@@ -55,7 +56,6 @@
#include "signal_catcher.h"
#include "signal_set.h"
#include "sirt_ref.h"
-#include "gc/space.h"
#include "thread.h"
#include "thread_list.h"
#include "trace.h"
@@ -210,29 +210,18 @@ void Runtime::Abort() {
LOG(INTERNAL_FATAL) << "Unexpectedly returned from abort hook!";
}
-#if defined(__BIONIC__)
- // TODO: finish merging patches to fix abort(3) in bionic, then lose this!
- // Bionic doesn't implement POSIX semantics for abort(3) in a multi-threaded
- // process, so if we call abort(3) on a device, all threads in the process
- // receive SIGABRT. debuggerd dumps the stack trace of the main
- // thread, whether or not that was the thread that failed. By
- // stuffing a value into a bogus address, we cause a segmentation
- // fault in the current thread, and get a useful log from debuggerd.
- // We can also trivially tell the difference between a crash and
- // a deliberate abort by looking at the fault address.
- *reinterpret_cast<char*>(0xdeadd00d) = 38;
-#elif defined(__APPLE__)
- // TODO: check that this actually gives good stack traces on the Mac!
- pthread_kill(pthread_self(), SIGABRT);
-#else
+#if defined(__GLIBC__)
// TODO: we ought to be able to use pthread_kill(3) here (or abort(3),
// which POSIX defines in terms of raise(3), which POSIX defines in terms
// of pthread_kill(3)). On Linux, though, libcorkscrew can't unwind through
// libpthread, which means the stacks we dump would be useless. Calling
// tgkill(2) directly avoids that.
syscall(__NR_tgkill, getpid(), GetTid(), SIGABRT);
- // TODO: LLVM installs it's own SIGABRT handler so exit to be safe... Can we disable that?
+ // TODO: LLVM installs it's own SIGABRT handler so exit to be safe... Can we disable that in LLVM?
+ // If not, we could use sigaction(3) before calling tgkill(2) and lose this call to exit(3).
exit(1);
+#else
+ abort();
#endif
// notreached
}
@@ -343,11 +332,11 @@ Runtime::ParsedOptions* Runtime::ParsedOptions::Create(const Options& options, b
// -Xcheck:jni is off by default for regular builds but on by default in debug builds.
parsed->check_jni_ = kIsDebugBuild;
- parsed->heap_initial_size_ = Heap::kDefaultInitialSize;
- parsed->heap_maximum_size_ = Heap::kDefaultMaximumSize;
- parsed->heap_min_free_ = Heap::kDefaultMinFree;
- parsed->heap_max_free_ = Heap::kDefaultMaxFree;
- parsed->heap_target_utilization_ = Heap::kDefaultTargetUtilization;
+ parsed->heap_initial_size_ = gc::Heap::kDefaultInitialSize;
+ parsed->heap_maximum_size_ = gc::Heap::kDefaultMaximumSize;
+ parsed->heap_min_free_ = gc::Heap::kDefaultMinFree;
+ parsed->heap_max_free_ = gc::Heap::kDefaultMaxFree;
+ parsed->heap_target_utilization_ = gc::Heap::kDefaultTargetUtilization;
parsed->heap_growth_limit_ = 0; // 0 means no growth limit.
parsed->stack_size_ = 0; // 0 means default.
@@ -368,6 +357,7 @@ Runtime::ParsedOptions* Runtime::ParsedOptions::Create(const Options& options, b
parsed->small_mode_method_threshold_ = Runtime::kDefaultSmallModeMethodThreshold;
parsed->small_mode_method_dex_size_limit_ = Runtime::kDefaultSmallModeMethodDexSizeLimit;
+ parsed->sea_ir_mode_ = false;
// gLogVerbosity.class_linker = true; // TODO: don't check this in!
// gLogVerbosity.compiler = true; // TODO: don't check this in!
// gLogVerbosity.heap = true; // TODO: don't check this in!
@@ -577,6 +567,8 @@ Runtime::ParsedOptions* Runtime::ParsedOptions::Create(const Options& options, b
Trace::SetDefaultClockSource(kProfilerClockSourceDual);
} else if (option == "-small") {
parsed->small_mode_ = true;
+ }else if (option == "-sea_ir") {
+ parsed->sea_ir_mode_ = true;
} else if (StartsWith(option, "-small-mode-methods-max:")) {
parsed->small_mode_method_threshold_ = ParseIntegerOrDie(option);
} else if (StartsWith(option, "-small-mode-methods-size-max:")) {
@@ -815,6 +807,7 @@ bool Runtime::Init(const Options& raw_options, bool ignore_unrecognized) {
small_mode_method_threshold_ = options->small_mode_method_threshold_;
small_mode_method_dex_size_limit_ = options->small_mode_method_dex_size_limit_;
+ sea_ir_mode_ = options->sea_ir_mode_;
vfprintf_ = options->hook_vfprintf_;
exit_ = options->hook_exit_;
abort_ = options->hook_abort_;
@@ -831,14 +824,14 @@ bool Runtime::Init(const Options& raw_options, bool ignore_unrecognized) {
GetInstrumentation()->ForceInterpretOnly();
}
- heap_ = new Heap(options->heap_initial_size_,
- options->heap_growth_limit_,
- options->heap_min_free_,
- options->heap_max_free_,
- options->heap_target_utilization_,
- options->heap_maximum_size_,
- options->image_,
- options->is_concurrent_gc_enabled_);
+ heap_ = new gc::Heap(options->heap_initial_size_,
+ options->heap_growth_limit_,
+ options->heap_min_free_,
+ options->heap_max_free_,
+ options->heap_target_utilization_,
+ options->heap_maximum_size_,
+ options->image_,
+ options->is_concurrent_gc_enabled_);
BlockSignals();
InitPlatformSignalHandlers();
@@ -860,8 +853,8 @@ bool Runtime::Init(const Options& raw_options, bool ignore_unrecognized) {
// Now we're attached, we can take the heap lock and validate the heap.
GetHeap()->EnableObjectValidation();
- CHECK_GE(GetHeap()->GetSpaces().size(), 1U);
- if (GetHeap()->GetSpaces()[0]->IsImageSpace()) {
+ CHECK_GE(GetHeap()->GetContinuousSpaces().size(), 1U);
+ if (GetHeap()->GetContinuousSpaces()[0]->IsImageSpace()) {
class_linker_ = ClassLinker::CreateFromImage(intern_table_);
} else {
CHECK(options->boot_class_path_ != NULL);
@@ -1073,12 +1066,13 @@ void Runtime::DetachCurrentThread() {
thread_list_->Unregister(self);
}
-void Runtime::VisitConcurrentRoots(RootVisitor* visitor, void* arg) {
- if (intern_table_->IsDirty()) {
- intern_table_->VisitRoots(visitor, arg);
+void Runtime::VisitConcurrentRoots(RootVisitor* visitor, void* arg, bool only_dirty,
+ bool clean_dirty) {
+ if (!only_dirty || intern_table_->IsDirty()) {
+ intern_table_->VisitRoots(visitor, arg, clean_dirty);
}
- if (class_linker_->IsDirty()) {
- class_linker_->VisitRoots(visitor, arg);
+ if (!only_dirty || class_linker_->IsDirty()) {
+ class_linker_->VisitRoots(visitor, arg, clean_dirty);
}
}
@@ -1098,15 +1092,8 @@ void Runtime::VisitNonConcurrentRoots(RootVisitor* visitor, void* arg) {
VisitNonThreadRoots(visitor, arg);
}
-void Runtime::DirtyRoots() {
- CHECK(intern_table_ != NULL);
- intern_table_->Dirty();
- CHECK(class_linker_ != NULL);
- class_linker_->Dirty();
-}
-
-void Runtime::VisitRoots(RootVisitor* visitor, void* arg) {
- VisitConcurrentRoots(visitor, arg);
+void Runtime::VisitRoots(RootVisitor* visitor, void* arg, bool only_dirty, bool clean_dirty) {
+ VisitConcurrentRoots(visitor, arg, only_dirty, clean_dirty);
VisitNonConcurrentRoots(visitor, arg);
}
@@ -1119,7 +1106,9 @@ mirror::AbstractMethod* Runtime::CreateResolutionMethod() {
// TODO: use a special method for resolution method saves
method->SetDexMethodIndex(DexFile::kDexNoIndex16);
// When compiling, the code pointer will get set later when the image is loaded.
- method->SetEntryPointFromCompiledCode(Runtime::Current()->IsCompiler() ? NULL : GetResolutionTrampoline());
+ Runtime* r = Runtime::Current();
+ ClassLinker* cl = r->GetClassLinker();
+ method->SetEntryPointFromCompiledCode(r->IsCompiler() ? NULL : GetResolutionTrampoline(cl));
return method.get();
}
diff --git a/src/runtime.h b/src/runtime.h
index 6f03fe0d68..0b893a341d 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -27,8 +27,8 @@
#include "base/macros.h"
#include "base/stringpiece.h"
+#include "gc/heap.h"
#include "globals.h"
-#include "heap.h"
#include "instruction_set.h"
#include "instrumentation.h"
#include "jobject_comparator.h"
@@ -39,17 +39,19 @@
namespace art {
+namespace gc {
+ class Heap;
+}
namespace mirror {
-class AbstractMethod;
-class ClassLoader;
-template<class T> class PrimitiveArray;
-typedef PrimitiveArray<int8_t> ByteArray;
-class String;
-class Throwable;
+ class AbstractMethod;
+ class ClassLoader;
+ template<class T> class PrimitiveArray;
+ typedef PrimitiveArray<int8_t> ByteArray;
+ class String;
+ class Throwable;
} // namespace mirror
class ClassLinker;
class DexFile;
-class Heap;
class InternTable;
struct JavaVMExt;
class MonitorList;
@@ -63,11 +65,13 @@ class Runtime {
// In small mode, apps with fewer than this number of methods will be compiled
// anyways.
+ // TODO: come up with a reasonable default.
static const size_t kDefaultSmallModeMethodThreshold = 0;
// In small mode, methods smaller than this dex op count limit will get compiled
// anyways.
- static const size_t kDefaultSmallModeMethodDexSizeLimit = 0;
+ // TODO: come up with a reasonable default.
+ static const size_t kDefaultSmallModeMethodDexSizeLimit = 300;
class ParsedOptions {
public:
@@ -104,9 +108,12 @@ class Runtime {
void (*hook_abort_)();
std::vector<std::string> properties_;
bool small_mode_;
+
size_t small_mode_method_threshold_;
size_t small_mode_method_dex_size_limit_;
+ bool sea_ir_mode_;
+
private:
ParsedOptions() {}
};
@@ -127,6 +134,14 @@ class Runtime {
return is_concurrent_gc_enabled_;
}
+ bool IsSeaIRMode() const {
+ return sea_ir_mode_;
+ }
+
+ void SetSeaIRMode(bool sea_ir_mode) {
+ sea_ir_mode_ = sea_ir_mode;
+ }
+
bool IsSmallMode() const {
return small_mode_;
}
@@ -222,7 +237,7 @@ class Runtime {
return default_stack_size_;
}
- Heap* GetHeap() const {
+ gc::Heap* GetHeap() const {
return heap_;
}
@@ -254,14 +269,13 @@ class Runtime {
return "2.0.0";
}
- // Force all the roots which can be marked concurrently to be dirty.
- void DirtyRoots();
-
- // Visit all the roots.
- void VisitRoots(RootVisitor* visitor, void* arg) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ // Visit all the roots. If only_dirty is true then non-dirty roots won't be visited. If
+ // clean_dirty is true then dirty roots will be marked as non-dirty after visiting.
+ void VisitRoots(RootVisitor* visitor, void* arg, bool only_dirty, bool clean_dirty)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Visit all of the roots we can do safely do concurrently.
- void VisitConcurrentRoots(RootVisitor* visitor, void* arg);
+ void VisitConcurrentRoots(RootVisitor* visitor, void* arg, bool only_dirty, bool clean_dirty);
// Visit all of the non thread roots, we can do this with mutators unpaused.
void VisitNonThreadRoots(RootVisitor* visitor, void* arg);
@@ -371,6 +385,8 @@ class Runtime {
size_t small_mode_method_threshold_;
size_t small_mode_method_dex_size_limit_;
+ bool sea_ir_mode_;
+
// The host prefix is used during cross compilation. It is removed
// from the start of host paths such as:
// $ANDROID_PRODUCT_OUT/system/framework/boot.oat
@@ -390,7 +406,7 @@ class Runtime {
// The default stack size for managed threads created by the runtime.
size_t default_stack_size_;
- Heap* heap_;
+ gc::Heap* heap_;
MonitorList* monitor_list_;
diff --git a/src/runtime_support.cc b/src/runtime_support.cc
index 9242c8790b..c933621981 100644
--- a/src/runtime_support.cc
+++ b/src/runtime_support.cc
@@ -18,7 +18,7 @@
#include "class_linker-inl.h"
#include "dex_file-inl.h"
-#include "gc/card_table-inl.h"
+#include "gc/accounting/card_table-inl.h"
#include "mirror/abstract_method-inl.h"
#include "mirror/class-inl.h"
#include "mirror/field-inl.h"
@@ -142,7 +142,8 @@ mirror::Array* CheckAndAllocArrayFromCode(uint32_t type_idx, mirror::AbstractMet
}
mirror::Field* FindFieldFromCode(uint32_t field_idx, const mirror::AbstractMethod* referrer,
- Thread* self, FindFieldType type, size_t expected_size) {
+ Thread* self, FindFieldType type, size_t expected_size,
+ bool access_check) {
bool is_primitive;
bool is_set;
bool is_static;
@@ -162,12 +163,13 @@ mirror::Field* FindFieldFromCode(uint32_t field_idx, const mirror::AbstractMetho
if (UNLIKELY(resolved_field == NULL)) {
DCHECK(self->IsExceptionPending()); // Throw exception and unwind.
return NULL; // Failure.
- } else {
+ }
+ mirror::Class* fields_class = resolved_field->GetDeclaringClass();
+ if (access_check) {
if (UNLIKELY(resolved_field->IsStatic() != is_static)) {
ThrowIncompatibleClassChangeErrorField(resolved_field, is_static, referrer);
return NULL;
}
- mirror::Class* fields_class = resolved_field->GetDeclaringClass();
mirror::Class* referring_class = referrer->GetDeclaringClass();
if (UNLIKELY(!referring_class->CanAccess(fields_class) ||
!referring_class->CanAccessMember(fields_class,
@@ -203,23 +205,24 @@ mirror::Field* FindFieldFromCode(uint32_t field_idx, const mirror::AbstractMetho
is_primitive ? "primitive" : "non-primitive",
PrettyField(resolved_field, true).c_str());
return NULL; // failure
- } else if (!is_static) {
- // instance fields must be being accessed on an initialized class
- return resolved_field;
- } else {
- // If the class is initialized we're done.
- if (fields_class->IsInitialized()) {
- return resolved_field;
- } else if (Runtime::Current()->GetClassLinker()->EnsureInitialized(fields_class, true, true)) {
- // Otherwise let's ensure the class is initialized before resolving the field.
- return resolved_field;
- } else {
- DCHECK(self->IsExceptionPending()); // Throw exception and unwind
- return NULL; // failure
- }
}
}
}
+ if (!is_static) {
+ // instance fields must be being accessed on an initialized class
+ return resolved_field;
+ } else {
+ // If the class is initialized we're done.
+ if (fields_class->IsInitialized()) {
+ return resolved_field;
+ } else if (Runtime::Current()->GetClassLinker()->EnsureInitialized(fields_class, true, true)) {
+ // Otherwise let's ensure the class is initialized before resolving the field.
+ return resolved_field;
+ } else {
+ DCHECK(self->IsExceptionPending()); // Throw exception and unwind
+ return NULL; // failure
+ }
+ }
}
// Slow path method resolution
diff --git a/src/runtime_support.h b/src/runtime_support.h
index 5fc8da53b6..0cb82a5466 100644
--- a/src/runtime_support.h
+++ b/src/runtime_support.h
@@ -34,14 +34,12 @@ extern "C" void art_interpreter_invoke_handler();
extern "C" void art_jni_dlsym_lookup_stub();
extern "C" void art_portable_abstract_method_error_stub();
extern "C" void art_portable_proxy_invoke_handler();
-extern "C" void art_portable_resolution_trampoline();
extern "C" void art_quick_abstract_method_error_stub();
extern "C" void art_quick_deoptimize();
extern "C" void art_quick_instrumentation_entry_from_code(void*);
extern "C" void art_quick_instrumentation_exit_from_code();
extern "C" void art_quick_interpreter_entry(void*);
extern "C" void art_quick_proxy_invoke_handler();
-extern "C" void art_quick_resolution_trampoline();
extern "C" void art_work_around_app_jni_bugs();
extern "C" double art_l2d(int64_t l);
@@ -146,7 +144,8 @@ enum FindFieldType {
// Slow field find that can initialize classes and may throw exceptions.
extern mirror::Field* FindFieldFromCode(uint32_t field_idx, const mirror::AbstractMethod* referrer,
- Thread* self, FindFieldType type, size_t expected_size)
+ Thread* self, FindFieldType type, size_t expected_size,
+ bool access_check)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Fast path field resolution that can't initialize classes or throw exceptions.
@@ -373,22 +372,20 @@ static inline void* GetInterpreterEntryPoint() {
return reinterpret_cast<void*>(art_quick_interpreter_entry);
}
-// Return address of portable resolution trampoline stub.
-static inline void* GetPortableResolutionTrampoline() {
- return reinterpret_cast<void*>(art_portable_resolution_trampoline);
+static inline const void* GetPortableResolutionTrampoline(ClassLinker* class_linker) {
+ return class_linker->GetPortableResolutionTrampoline();
}
-// Return address of quick resolution trampoline stub.
-static inline void* GetQuickResolutionTrampoline() {
- return reinterpret_cast<void*>(art_quick_resolution_trampoline);
+static inline const void* GetQuickResolutionTrampoline(ClassLinker* class_linker) {
+ return class_linker->GetQuickResolutionTrampoline();
}
// Return address of resolution trampoline stub for defined compiler.
-static inline void* GetResolutionTrampoline() {
+static inline const void* GetResolutionTrampoline(ClassLinker* class_linker) {
#if defined(ART_USE_PORTABLE_COMPILER)
- return GetPortableResolutionTrampoline();
+ return GetPortableResolutionTrampoline(class_linker);
#else
- return GetQuickResolutionTrampoline();
+ return GetQuickResolutionTrampoline(class_linker);
#endif
}
diff --git a/src/signal_catcher.cc b/src/signal_catcher.cc
index c021dd1d2c..a630db810a 100644
--- a/src/signal_catcher.cc
+++ b/src/signal_catcher.cc
@@ -27,7 +27,7 @@
#include "base/unix_file/fd_file.h"
#include "class_linker.h"
-#include "heap.h"
+#include "gc/heap.h"
#include "os.h"
#include "runtime.h"
#include "scoped_thread_state_change.h"
diff --git a/src/stack.cc b/src/stack.cc
index 8690a36387..8672975453 100644
--- a/src/stack.cc
+++ b/src/stack.cc
@@ -42,6 +42,15 @@ mirror::Object* ShadowFrame::GetThisObject() const {
}
}
+mirror::Object* ShadowFrame::GetThisObject(uint16_t num_ins) const {
+ mirror::AbstractMethod* m = GetMethod();
+ if (m->IsStatic()) {
+ return NULL;
+ } else {
+ return GetVRegReference(NumberOfVRegs() - num_ins);
+ }
+}
+
ThrowLocation ShadowFrame::GetCurrentLocationForThrow() const {
return ThrowLocation(GetThisObject(), GetMethod(), GetDexPC());
}
diff --git a/src/stack.h b/src/stack.h
index 1b4d285216..fbfacb1733 100644
--- a/src/stack.h
+++ b/src/stack.h
@@ -202,6 +202,8 @@ class ShadowFrame {
mirror::Object* GetThisObject() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ mirror::Object* GetThisObject(uint16_t num_ins) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
ThrowLocation GetCurrentLocationForThrow() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
void SetMethod(mirror::AbstractMethod* method) {
@@ -254,13 +256,9 @@ class ShadowFrame {
CHECK_LT(num_vregs, static_cast<uint32_t>(kHasReferenceArray));
number_of_vregs_ |= kHasReferenceArray;
#endif
- for (size_t i = 0; i < num_vregs; ++i) {
- SetVRegReference(i, NULL);
- }
+ memset(vregs_, 0, num_vregs * (sizeof(uint32_t) + sizeof(mirror::Object*)));
} else {
- for (size_t i = 0; i < num_vregs; ++i) {
- SetVReg(i, 0);
- }
+ memset(vregs_, 0, num_vregs * sizeof(uint32_t));
}
}
diff --git a/src/thread-inl.h b/src/thread-inl.h
index 6c1ae59b60..2fc5987306 100644
--- a/src/thread-inl.h
+++ b/src/thread-inl.h
@@ -125,7 +125,7 @@ inline ThreadState Thread::TransitionFromSuspendedToRunnable() {
}
inline void Thread::VerifyStack() {
- Heap* heap = Runtime::Current()->GetHeap();
+ gc::Heap* heap = Runtime::Current()->GetHeap();
if (heap->IsObjectValidationEnabled()) {
VerifyStackImpl();
}
diff --git a/src/thread.cc b/src/thread.cc
index c5bfb20ddb..d6bd8a45a6 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -14,8 +14,11 @@
* limitations under the License.
*/
+#define ATRACE_TAG ATRACE_TAG_DALVIK
+
#include "thread.h"
+#include <cutils/trace.h>
#include <pthread.h>
#include <signal.h>
#include <sys/resource.h>
@@ -35,8 +38,9 @@
#include "debugger.h"
#include "dex_file-inl.h"
#include "gc_map.h"
-#include "gc/card_table-inl.h"
-#include "heap.h"
+#include "gc/accounting/card_table-inl.h"
+#include "gc/heap.h"
+#include "gc/space/space.h"
#include "invoke_arg_array_builder.h"
#include "jni_internal.h"
#include "mirror/abstract_method-inl.h"
@@ -53,8 +57,8 @@
#include "runtime_support.h"
#include "scoped_thread_state_change.h"
#include "ScopedLocalRef.h"
+#include "ScopedUtfChars.h"
#include "sirt_ref.h"
-#include "gc/space.h"
#include "stack.h"
#include "stack_indirect_reference_table.h"
#include "thread-inl.h"
@@ -169,7 +173,7 @@ void* Thread::CreateCallback(void* arg) {
Thread* Thread::FromManagedThread(const ScopedObjectAccessUnchecked& soa,
mirror::Object* thread_peer) {
- mirror::Field* f = soa.DecodeField(WellKnownClasses::java_lang_Thread_vmData);
+ mirror::Field* f = soa.DecodeField(WellKnownClasses::java_lang_Thread_nativePeer);
Thread* result = reinterpret_cast<Thread*>(static_cast<uintptr_t>(f->GetInt(thread_peer)));
// Sanity check that if we have a result it is either suspended or we hold the thread_list_lock_
// to stop it from going away.
@@ -275,9 +279,9 @@ void Thread::CreateNativeThread(JNIEnv* env, jobject java_peer, size_t stack_siz
child_thread->jpeer_ = env->NewGlobalRef(java_peer);
stack_size = FixStackSize(stack_size);
- // Thread.start is synchronized, so we know that vmData is 0, and know that we're not racing to
+ // Thread.start is synchronized, so we know that nativePeer is 0, and know that we're not racing to
// assign it.
- env->SetIntField(java_peer, WellKnownClasses::java_lang_Thread_vmData,
+ env->SetIntField(java_peer, WellKnownClasses::java_lang_Thread_nativePeer,
reinterpret_cast<jint>(child_thread));
pthread_t new_pthread;
@@ -300,7 +304,7 @@ void Thread::CreateNativeThread(JNIEnv* env, jobject java_peer, size_t stack_siz
delete child_thread;
child_thread = NULL;
// TODO: remove from thread group?
- env->SetIntField(java_peer, WellKnownClasses::java_lang_Thread_vmData, 0);
+ env->SetIntField(java_peer, WellKnownClasses::java_lang_Thread_nativePeer, 0);
{
std::string msg(StringPrintf("pthread_create (%s stack) failed: %s",
PrettySize(stack_size).c_str(), strerror(pthread_create_result)));
@@ -405,7 +409,7 @@ void Thread::CreatePeer(const char* name, bool as_daemon, jobject thread_group)
Thread* self = this;
DCHECK_EQ(self, Thread::Current());
- jni_env_->SetIntField(peer.get(), WellKnownClasses::java_lang_Thread_vmData,
+ jni_env_->SetIntField(peer.get(), WellKnownClasses::java_lang_Thread_nativePeer,
reinterpret_cast<jint>(self));
ScopedObjectAccess soa(self);
@@ -573,6 +577,13 @@ void Thread::ModifySuspendCount(Thread* self, int delta, bool for_debugger) {
}
}
+void Thread::RunCheckpointFunction() {
+ CHECK(checkpoint_function_ != NULL);
+ ATRACE_BEGIN("Checkpoint function");
+ checkpoint_function_->Run(this);
+ ATRACE_END();
+}
+
bool Thread::RequestCheckpoint(Closure* function) {
CHECK(!ReadFlag(kCheckpointRequest)) << "Already have a pending checkpoint request";
checkpoint_function_ = function;
@@ -588,10 +599,12 @@ bool Thread::RequestCheckpoint(Closure* function) {
void Thread::FullSuspendCheck() {
VLOG(threads) << this << " self-suspending";
+ ATRACE_BEGIN("Full suspend check");
// Make thread appear suspended to other threads, release mutator_lock_.
TransitionFromRunnableToSuspended(kSuspended);
// Transition back to runnable noting requests to suspend, re-acquire share on mutator_lock_.
TransitionFromSuspendedToRunnable();
+ ATRACE_END();
VLOG(threads) << this << " self-reviving";
}
@@ -605,10 +618,22 @@ Thread* Thread::SuspendForDebugger(jobject peer, bool request_suspension, bool*
Thread* thread;
{
ScopedObjectAccess soa(Thread::Current());
- MutexLock mu(soa.Self(), *Locks::thread_list_lock_);
+ Thread* self = soa.Self();
+ MutexLock mu(self, *Locks::thread_list_lock_);
thread = Thread::FromManagedThread(soa, peer);
if (thread == NULL) {
- LOG(WARNING) << "No such thread for suspend: " << peer;
+ JNIEnv* env = self->GetJniEnv();
+ ScopedLocalRef<jstring> scoped_name_string(env,
+ (jstring)env->GetObjectField(peer,
+ WellKnownClasses::java_lang_Thread_name));
+ ScopedUtfChars scoped_name_chars(env,scoped_name_string.get());
+ if (scoped_name_chars.c_str() == NULL) {
+ LOG(WARNING) << "No such thread for suspend: " << peer;
+ env->ExceptionClear();
+ } else {
+ LOG(WARNING) << "No such thread for suspend: " << peer << ":" << scoped_name_chars.c_str();
+ }
+
return NULL;
}
{
@@ -865,9 +890,10 @@ void Thread::DumpStack(std::ostream& os) const {
// TODO: we call this code when dying but may not have suspended the thread ourself. The
// IsSuspended check is therefore racy with the use for dumping (normally we inhibit
// the race with the thread_suspend_count_lock_).
- if (this == Thread::Current() || IsSuspended()) {
+ bool dump_for_abort = (gAborting > 0);
+ if (this == Thread::Current() || IsSuspended() || dump_for_abort) {
// If we're currently in native code, dump that stack before dumping the managed stack.
- if (ShouldShowNativeStack(this)) {
+ if (dump_for_abort || ShouldShowNativeStack(this)) {
DumpKernelStack(os, GetTid(), " kernel: ", false);
DumpNativeStack(os, GetTid(), " native: ", false);
}
@@ -1013,8 +1039,8 @@ void Thread::Destroy() {
HandleUncaughtExceptions(soa);
RemoveFromThreadGroup(soa);
- // this.vmData = 0;
- soa.DecodeField(WellKnownClasses::java_lang_Thread_vmData)->SetInt(opeer_, 0);
+ // this.nativePeer = 0;
+ soa.DecodeField(WellKnownClasses::java_lang_Thread_nativePeer)->SetInt(opeer_, 0);
Dbg::PostThreadDeath(self);
// Thread.join() is implemented as an Object.wait() on the Thread.lock object. Signal anyone
@@ -1643,10 +1669,14 @@ static const EntryPointInfo gThreadEntryPointInfo[] = {
ENTRY_POINT_INFO(pShlLong),
ENTRY_POINT_INFO(pShrLong),
ENTRY_POINT_INFO(pUshrLong),
+ ENTRY_POINT_INFO(pInterpreterToInterpreterEntry),
+ ENTRY_POINT_INFO(pInterpreterToQuickEntry),
ENTRY_POINT_INFO(pIndexOf),
ENTRY_POINT_INFO(pMemcmp16),
ENTRY_POINT_INFO(pStringCompareTo),
ENTRY_POINT_INFO(pMemcpy),
+ ENTRY_POINT_INFO(pPortableResolutionTrampolineFromCode),
+ ENTRY_POINT_INFO(pQuickResolutionTrampolineFromCode),
ENTRY_POINT_INFO(pInvokeDirectTrampolineWithAccessCheck),
ENTRY_POINT_INFO(pInvokeInterfaceTrampoline),
ENTRY_POINT_INFO(pInvokeInterfaceTrampolineWithAccessCheck),
@@ -2180,7 +2210,7 @@ void Thread::VisitRoots(RootVisitor* visitor, void* arg) {
}
static void VerifyObject(const mirror::Object* root, void* arg) {
- Heap* heap = reinterpret_cast<Heap*>(arg);
+ gc::Heap* heap = reinterpret_cast<gc::Heap*>(arg);
heap->VerifyObject(root);
}
diff --git a/src/thread.h b/src/thread.h
index 24987cd441..0daf763359 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -554,10 +554,7 @@ class PACKED(4) Thread {
held_mutexes_[level] = mutex;
}
- void RunCheckpointFunction() {
- CHECK(checkpoint_function_ != NULL);
- checkpoint_function_->Run(this);
- }
+ void RunCheckpointFunction();
bool ReadFlag(ThreadFlag flag) const {
return (state_and_flags_.as_struct.flags & flag) != 0;
diff --git a/src/thread_list.cc b/src/thread_list.cc
index ebb63ddc1f..eacd848171 100644
--- a/src/thread_list.cc
+++ b/src/thread_list.cc
@@ -466,10 +466,8 @@ void ThreadList::WaitForOtherNonDaemonThreadsToExit() {
all_threads_are_daemons = true;
MutexLock mu(self, *Locks::thread_list_lock_);
for (It it = list_.begin(), end = list_.end(); it != end; ++it) {
- // TODO: there's a race here with thread exit that's being worked around by checking if the
- // thread has a peer.
Thread* thread = *it;
- if (thread != self && thread->HasPeer() && !thread->IsDaemon()) {
+ if (thread != self && !thread->IsDaemon()) {
all_threads_are_daemons = false;
break;
}
diff --git a/src/thread_pool.cc b/src/thread_pool.cc
index 370e4bcc20..f0f6f1844d 100644
--- a/src/thread_pool.cc
+++ b/src/thread_pool.cc
@@ -154,17 +154,22 @@ Task* ThreadPool::TryGetTaskLocked(Thread* self) {
return NULL;
}
-void ThreadPool::Wait(Thread* self, bool do_work) {
- Task* task = NULL;
- while ((task = TryGetTask(self)) != NULL) {
- task->Run(self);
- task->Finalize();
+void ThreadPool::Wait(Thread* self, bool do_work, bool may_hold_locks) {
+ if (do_work) {
+ Task* task = NULL;
+ while ((task = TryGetTask(self)) != NULL) {
+ task->Run(self);
+ task->Finalize();
+ }
}
-
// Wait until each thread is waiting and the task list is empty.
MutexLock mu(self, task_queue_lock_);
while (!shutting_down_ && (waiting_count_ != GetThreadCount() || !tasks_.empty())) {
- completion_condition_.Wait(self);
+ if (!may_hold_locks) {
+ completion_condition_.Wait(self);
+ } else {
+ completion_condition_.WaitHoldingLocks(self);
+ }
}
}
diff --git a/src/thread_pool.h b/src/thread_pool.h
index 18af97dfa3..814e654ad7 100644
--- a/src/thread_pool.h
+++ b/src/thread_pool.h
@@ -80,7 +80,7 @@ class ThreadPool {
virtual ~ThreadPool();
// Wait for all tasks currently on queue to get completed.
- void Wait(Thread* self, bool do_work = true);
+ void Wait(Thread* self, bool do_work, bool may_hold_locks);
size_t GetTaskCount(Thread* self);
diff --git a/src/thread_pool_test.cc b/src/thread_pool_test.cc
index e056935319..e2a32f510d 100644
--- a/src/thread_pool_test.cc
+++ b/src/thread_pool_test.cc
@@ -68,7 +68,7 @@ TEST_F(ThreadPoolTest, CheckRun) {
}
thread_pool.StartWorkers(self);
// Wait for tasks to complete.
- thread_pool.Wait(self);
+ thread_pool.Wait(self, true, false);
// Make sure that we finished all the work.
EXPECT_EQ(num_tasks, count);
}
@@ -137,7 +137,7 @@ TEST_F(ThreadPoolTest, RecursiveTest) {
static const int depth = 8;
thread_pool.AddTask(self, new TreeTask(&thread_pool, &count, depth));
thread_pool.StartWorkers(self);
- thread_pool.Wait(self);
+ thread_pool.Wait(self, true, false);
EXPECT_EQ((1 << depth) - 1, count);
}
diff --git a/src/thread_state.h b/src/thread_state.h
index 7c4a16f914..52f092efa0 100644
--- a/src/thread_state.h
+++ b/src/thread_state.h
@@ -28,6 +28,7 @@ enum ThreadState {
kBlocked, // BLOCKED TS_MONITOR blocked on a monitor
kWaiting, // WAITING TS_WAIT in Object.wait()
kWaitingForGcToComplete, // WAITING TS_WAIT blocked waiting for GC
+ kWaitingForCheckPointsToRun, // WAITING TS_WAIT GC waiting for checkpoints to run
kWaitingPerformingGc, // WAITING TS_WAIT performing GC
kWaitingForDebuggerSend, // WAITING TS_WAIT blocked waiting for events to be sent
kWaitingForDebuggerToAttach, // WAITING TS_WAIT blocked waiting for debugger to attach
diff --git a/src/utf.cc b/src/utf.cc
index 8d3547e70c..1add7d9a68 100644
--- a/src/utf.cc
+++ b/src/utf.cc
@@ -119,6 +119,23 @@ int CompareModifiedUtf8ToModifiedUtf8AsUtf16CodePointValues(const char* utf8_1,
}
}
+int CompareModifiedUtf8ToUtf16AsCodePointValues(const char* utf8_1, const uint16_t* utf8_2) {
+ for (;;) {
+ if (*utf8_1 == '\0') {
+ return (*utf8_2 == '\0') ? 0 : -1;
+ } else if (*utf8_2 == '\0') {
+ return 1;
+ }
+
+ int c1 = GetUtf16FromUtf8(&utf8_1);
+ int c2 = *utf8_2;
+
+ if (c1 != c2) {
+ return c1 > c2 ? 1 : -1;
+ }
+ }
+}
+
size_t CountUtf8Bytes(const uint16_t* chars, size_t char_count) {
size_t result = 0;
while (char_count--) {
diff --git a/src/utf.h b/src/utf.h
index 44899bfdd2..57c811f21d 100644
--- a/src/utf.h
+++ b/src/utf.h
@@ -56,6 +56,12 @@ void ConvertModifiedUtf8ToUtf16(uint16_t* utf16_out, const char* utf8_in);
int CompareModifiedUtf8ToModifiedUtf8AsUtf16CodePointValues(const char* utf8_1, const char* utf8_2);
/*
+ * Compare a modified UTF-8 string with a UTF-16 string as code point values in a non-locale
+ * sensitive manner.
+ */
+int CompareModifiedUtf8ToUtf16AsCodePointValues(const char* utf8_1, const uint16_t* utf8_2);
+
+/*
* Convert from UTF-16 to Modified UTF-8. Note that the output is _not_
* NUL-terminated. You probably need to call CountUtf8Bytes before calling
* this anyway, so if you want a NUL-terminated string, you know where to
diff --git a/src/vector_output_stream.cc b/src/vector_output_stream.cc
index 96154ee92b..e5ff729036 100644
--- a/src/vector_output_stream.cc
+++ b/src/vector_output_stream.cc
@@ -16,8 +16,6 @@
#include "vector_output_stream.h"
-#include <string.h>
-
#include "base/logging.h"
namespace art {
@@ -25,14 +23,6 @@ namespace art {
VectorOutputStream::VectorOutputStream(const std::string& location, std::vector<uint8_t>& vector)
: OutputStream(location), offset_(vector.size()), vector_(vector) {}
-bool VectorOutputStream::WriteFully(const void* buffer, int64_t byte_count) {
- off_t new_offset = offset_ + byte_count;
- EnsureCapacity(new_offset);
- memcpy(&vector_[offset_], buffer, byte_count);
- offset_ = new_offset;
- return true;
-}
-
off_t VectorOutputStream::Seek(off_t offset, Whence whence) {
CHECK(whence == kSeekSet || whence == kSeekCurrent || whence == kSeekEnd) << whence;
off_t new_offset = 0;
@@ -55,10 +45,4 @@ off_t VectorOutputStream::Seek(off_t offset, Whence whence) {
return offset_;
}
-void VectorOutputStream::EnsureCapacity(off_t new_offset) {
- if (new_offset > static_cast<off_t>(vector_.size())) {
- vector_.resize(new_offset);
- }
-}
-
} // namespace art
diff --git a/src/vector_output_stream.h b/src/vector_output_stream.h
index a99128e6f3..3546c8d577 100644
--- a/src/vector_output_stream.h
+++ b/src/vector_output_stream.h
@@ -20,6 +20,7 @@
#include "output_stream.h"
#include <string>
+#include <string.h>
#include <vector>
namespace art {
@@ -30,12 +31,28 @@ class VectorOutputStream : public OutputStream {
virtual ~VectorOutputStream() {}
- virtual bool WriteFully(const void* buffer, int64_t byte_count);
+ bool WriteFully(const void* buffer, int64_t byte_count) {
+ if (static_cast<size_t>(offset_) == vector_.size()) {
+ const uint8_t* start = reinterpret_cast<const uint8_t*>(buffer);
+ vector_.insert(vector_.end(), &start[0], &start[byte_count]);
+ offset_ += byte_count;
+ } else {
+ off_t new_offset = offset_ + byte_count;
+ EnsureCapacity(new_offset);
+ memcpy(&vector_[offset_], buffer, byte_count);
+ offset_ = new_offset;
+ }
+ return true;
+ }
- virtual off_t Seek(off_t offset, Whence whence);
+ off_t Seek(off_t offset, Whence whence);
private:
- void EnsureCapacity(off_t new_offset);
+ void EnsureCapacity(off_t new_offset) {
+ if (new_offset > static_cast<off_t>(vector_.size())) {
+ vector_.resize(new_offset);
+ }
+ }
off_t offset_;
std::vector<uint8_t>& vector_;
diff --git a/src/verifier/method_verifier.cc b/src/verifier/method_verifier.cc
index 2eb0c203ea..74a79e0ae2 100644
--- a/src/verifier/method_verifier.cc
+++ b/src/verifier/method_verifier.cc
@@ -19,24 +19,26 @@
#include <iostream>
#include "base/logging.h"
+#include "base/mutex-inl.h"
#include "base/stringpiece.h"
#include "class_linker.h"
#include "compiler/driver/compiler_driver.h"
#include "dex_file-inl.h"
-#include "dex_instruction.h"
+#include "dex_instruction-inl.h"
#include "dex_instruction_visitor.h"
-#include "gc/card_table-inl.h"
+#include "gc/accounting/card_table-inl.h"
#include "indenter.h"
#include "intern_table.h"
#include "leb128.h"
#include "mirror/abstract_method-inl.h"
#include "mirror/class.h"
#include "mirror/class-inl.h"
-#include "mirror/dex_cache.h"
+#include "mirror/dex_cache-inl.h"
#include "mirror/field-inl.h"
#include "mirror/object-inl.h"
#include "mirror/object_array-inl.h"
#include "object_utils.h"
+#include "register_line-inl.h"
#include "runtime.h"
#include "verifier/dex_gc_map.h"
@@ -266,13 +268,14 @@ MethodVerifier::MethodVerifier(const DexFile* dex_file, mirror::DexCache* dex_ca
: reg_types_(can_load_classes),
work_insn_idx_(-1),
dex_method_idx_(dex_method_idx),
- foo_method_(method),
+ mirror_method_(method),
method_access_flags_(method_access_flags),
dex_file_(dex_file),
dex_cache_(dex_cache),
class_loader_(class_loader),
class_def_idx_(class_def_idx),
code_item_(code_item),
+ declaring_class_(NULL),
interesting_dex_pc_(-1),
monitor_enter_dex_pcs_(NULL),
have_pending_hard_failure_(false),
@@ -305,6 +308,63 @@ void MethodVerifier::FindLocksAtDexPc() {
Verify();
}
+mirror::Field* MethodVerifier::FindAccessedFieldAtDexPc(mirror::AbstractMethod* m,
+ uint32_t dex_pc) {
+ MethodHelper mh(m);
+ MethodVerifier verifier(&mh.GetDexFile(), mh.GetDexCache(), mh.GetClassLoader(),
+ mh.GetClassDefIndex(), mh.GetCodeItem(), m->GetDexMethodIndex(),
+ m, m->GetAccessFlags(), false, true);
+ return verifier.FindAccessedFieldAtDexPc(dex_pc);
+}
+
+mirror::Field* MethodVerifier::FindAccessedFieldAtDexPc(uint32_t dex_pc) {
+ CHECK(code_item_ != NULL); // This only makes sense for methods with code.
+
+ // Strictly speaking, we ought to be able to get away with doing a subset of the full method
+ // verification. In practice, the phase we want relies on data structures set up by all the
+ // earlier passes, so we just run the full method verification and bail out early when we've
+ // got what we wanted.
+ bool success = Verify();
+ if (!success) {
+ return NULL;
+ }
+ RegisterLine* register_line = reg_table_.GetLine(dex_pc);
+ if (register_line == NULL) {
+ return NULL;
+ }
+ const Instruction* inst = Instruction::At(code_item_->insns_ + dex_pc);
+ return GetQuickFieldAccess(inst, register_line);
+}
+
+mirror::AbstractMethod* MethodVerifier::FindInvokedMethodAtDexPc(mirror::AbstractMethod* m,
+ uint32_t dex_pc) {
+ MethodHelper mh(m);
+ MethodVerifier verifier(&mh.GetDexFile(), mh.GetDexCache(), mh.GetClassLoader(),
+ mh.GetClassDefIndex(), mh.GetCodeItem(), m->GetDexMethodIndex(),
+ m, m->GetAccessFlags(), false, true);
+ return verifier.FindInvokedMethodAtDexPc(dex_pc);
+}
+
+mirror::AbstractMethod* MethodVerifier::FindInvokedMethodAtDexPc(uint32_t dex_pc) {
+ CHECK(code_item_ != NULL); // This only makes sense for methods with code.
+
+ // Strictly speaking, we ought to be able to get away with doing a subset of the full method
+ // verification. In practice, the phase we want relies on data structures set up by all the
+ // earlier passes, so we just run the full method verification and bail out early when we've
+ // got what we wanted.
+ bool success = Verify();
+ if (!success) {
+ return NULL;
+ }
+ RegisterLine* register_line = reg_table_.GetLine(dex_pc);
+ if (register_line == NULL) {
+ return NULL;
+ }
+ const Instruction* inst = Instruction::At(code_item_->insns_ + dex_pc);
+ const bool is_range = (inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE_QUICK);
+ return GetQuickInvokedMethod(inst, register_line, is_range);
+}
+
bool MethodVerifier::Verify() {
// If there aren't any instructions, make sure that's expected, then exit successfully.
if (code_item_ == NULL) {
@@ -895,6 +955,7 @@ bool MethodVerifier::CheckVarArgRangeRegs(uint32_t vA, uint32_t vC) {
static const std::vector<uint8_t>* CreateLengthPrefixedDexGcMap(const std::vector<uint8_t>& gc_map) {
std::vector<uint8_t>* length_prefixed_gc_map = new std::vector<uint8_t>;
+ length_prefixed_gc_map->reserve(gc_map.size() + 4);
length_prefixed_gc_map->push_back((gc_map.size() & 0xff000000) >> 24);
length_prefixed_gc_map->push_back((gc_map.size() & 0x00ff0000) >> 16);
length_prefixed_gc_map->push_back((gc_map.size() & 0x0000ff00) >> 8);
@@ -949,15 +1010,20 @@ bool MethodVerifier::VerifyCodeFlow() {
DCHECK_NE(failures_.size(), 0U);
return false; // Not a real failure, but a failure to encode
}
-#ifndef NDEBUG
- VerifyGcMap(*map);
-#endif
+ if (kIsDebugBuild) {
+ VerifyGcMap(*map);
+ }
const std::vector<uint8_t>* dex_gc_map = CreateLengthPrefixedDexGcMap(*(map.get()));
verifier::MethodVerifier::SetDexGcMap(ref, *dex_gc_map);
- MethodVerifier::PcToConreteMethod* pc_to_conrete_method = GenerateDevirtMap();
- if(pc_to_conrete_method != NULL ) {
- SetDevirtMap(ref, pc_to_conrete_method);
+ MethodVerifier::MethodSafeCastSet* method_to_safe_casts = GenerateSafeCastSet();
+ if(method_to_safe_casts != NULL ) {
+ SetSafeCastMap(ref, method_to_safe_casts);
+ }
+
+ MethodVerifier::PcToConcreteMethodMap* pc_to_concrete_method = GenerateDevirtMap();
+ if(pc_to_concrete_method != NULL ) {
+ SetDevirtMap(ref, pc_to_concrete_method);
}
return true;
}
@@ -1244,6 +1310,11 @@ bool MethodVerifier::CodeFlowVerifyMethod() {
if (dead_start >= 0) {
LogVerifyInfo() << "dead code " << reinterpret_cast<void*>(dead_start) << "-" << reinterpret_cast<void*>(insn_idx - 1);
}
+ // To dump the state of the verify after a method, do something like:
+ // if (PrettyMethod(dex_method_idx_, *dex_file_) ==
+ // "boolean java.lang.String.equals(java.lang.Object)") {
+ // LOG(INFO) << info_messages_.str();
+ // }
}
return true;
}
@@ -1280,7 +1351,6 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
*/
const uint16_t* insns = code_item_->insns_ + work_insn_idx_;
const Instruction* inst = Instruction::At(insns);
- DecodedInstruction dec_insn(inst);
int opcode_flags = Instruction::FlagsOf(inst->Opcode());
int32_t branch_target = 0;
@@ -1306,32 +1376,51 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
#endif
}
- switch (dec_insn.opcode) {
+
+ // We need to ensure the work line is consistent while performing validation. When we spot a
+ // peephole pattern we compute a new line for either the fallthrough instruction or the
+ // branch target.
+ UniquePtr<RegisterLine> branch_line;
+ UniquePtr<RegisterLine> fallthrough_line;
+
+ switch (inst->Opcode()) {
case Instruction::NOP:
/*
* A "pure" NOP has no effect on anything. Data tables start with
* a signature that looks like a NOP; if we see one of these in
* the course of executing code then we have a problem.
*/
- if (dec_insn.vA != 0) {
+ if (inst->VRegA_10x() != 0) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "encountered data table in instruction stream";
}
break;
case Instruction::MOVE:
+ work_line_->CopyRegister1(inst->VRegA_12x(), inst->VRegB_12x(), kTypeCategory1nr);
+ break;
case Instruction::MOVE_FROM16:
+ work_line_->CopyRegister1(inst->VRegA_22x(), inst->VRegB_22x(), kTypeCategory1nr);
+ break;
case Instruction::MOVE_16:
- work_line_->CopyRegister1(dec_insn.vA, dec_insn.vB, kTypeCategory1nr);
+ work_line_->CopyRegister1(inst->VRegA_32x(), inst->VRegB_32x(), kTypeCategory1nr);
break;
case Instruction::MOVE_WIDE:
+ work_line_->CopyRegister2(inst->VRegA_12x(), inst->VRegB_12x());
+ break;
case Instruction::MOVE_WIDE_FROM16:
+ work_line_->CopyRegister2(inst->VRegA_22x(), inst->VRegB_22x());
+ break;
case Instruction::MOVE_WIDE_16:
- work_line_->CopyRegister2(dec_insn.vA, dec_insn.vB);
+ work_line_->CopyRegister2(inst->VRegA_32x(), inst->VRegB_32x());
break;
case Instruction::MOVE_OBJECT:
+ work_line_->CopyRegister1(inst->VRegA_12x(), inst->VRegB_12x(), kTypeCategoryRef);
+ break;
case Instruction::MOVE_OBJECT_FROM16:
+ work_line_->CopyRegister1(inst->VRegA_22x(), inst->VRegB_22x(), kTypeCategoryRef);
+ break;
case Instruction::MOVE_OBJECT_16:
- work_line_->CopyRegister1(dec_insn.vA, dec_insn.vB, kTypeCategoryRef);
+ work_line_->CopyRegister1(inst->VRegA_32x(), inst->VRegB_32x(), kTypeCategoryRef);
break;
/*
@@ -1346,13 +1435,13 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
* easier to read in some cases.)
*/
case Instruction::MOVE_RESULT:
- work_line_->CopyResultRegister1(dec_insn.vA, false);
+ work_line_->CopyResultRegister1(inst->VRegA_11x(), false);
break;
case Instruction::MOVE_RESULT_WIDE:
- work_line_->CopyResultRegister2(dec_insn.vA);
+ work_line_->CopyResultRegister2(inst->VRegA_11x());
break;
case Instruction::MOVE_RESULT_OBJECT:
- work_line_->CopyResultRegister1(dec_insn.vA, true);
+ work_line_->CopyResultRegister1(inst->VRegA_11x(), true);
break;
case Instruction::MOVE_EXCEPTION: {
@@ -1361,7 +1450,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
* that as part of extracting the exception type from the catch block list.
*/
const RegType& res_type = GetCaughtExceptionType();
- work_line_->SetRegisterType(dec_insn.vA, res_type);
+ work_line_->SetRegisterType(inst->VRegA_11x(), res_type);
break;
}
case Instruction::RETURN_VOID:
@@ -1380,16 +1469,17 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
} else {
// Compilers may generate synthetic functions that write byte values into boolean fields.
// Also, it may use integer values for boolean, byte, short, and character return types.
- const RegType& src_type = work_line_->GetRegisterType(dec_insn.vA);
+ const uint32_t vregA = inst->VRegA_11x();
+ const RegType& src_type = work_line_->GetRegisterType(vregA);
bool use_src = ((return_type.IsBoolean() && src_type.IsByte()) ||
((return_type.IsBoolean() || return_type.IsByte() ||
return_type.IsShort() || return_type.IsChar()) &&
src_type.IsInteger()));
/* check the register contents */
bool success =
- work_line_->VerifyRegisterType(dec_insn.vA, use_src ? src_type : return_type);
+ work_line_->VerifyRegisterType(vregA, use_src ? src_type : return_type);
if (!success) {
- AppendToLastFailMessage(StringPrintf(" return-1nr on invalid register v%d", dec_insn.vA));
+ AppendToLastFailMessage(StringPrintf(" return-1nr on invalid register v%d", vregA));
}
}
}
@@ -1402,9 +1492,10 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "return-wide not expected";
} else {
/* check the register contents */
- bool success = work_line_->VerifyRegisterType(dec_insn.vA, return_type);
+ const uint32_t vregA = inst->VRegA_11x();
+ bool success = work_line_->VerifyRegisterType(vregA, return_type);
if (!success) {
- AppendToLastFailMessage(StringPrintf(" return-wide on invalid register v%d", dec_insn.vA));
+ AppendToLastFailMessage(StringPrintf(" return-wide on invalid register v%d", vregA));
}
}
}
@@ -1418,7 +1509,8 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
/* return_type is the *expected* return type, not register value */
DCHECK(!return_type.IsZero());
DCHECK(!return_type.IsUninitializedReference());
- const RegType& reg_type = work_line_->GetRegisterType(dec_insn.vA);
+ const uint32_t vregA = inst->VRegA_11x();
+ const RegType& reg_type = work_line_->GetRegisterType(vregA);
// Disallow returning uninitialized values and verify that the reference in vAA is an
// instance of the "return_type"
if (reg_type.IsUninitializedTypes()) {
@@ -1432,66 +1524,71 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
break;
/* could be boolean, int, float, or a null reference */
- case Instruction::CONST_4:
- work_line_->SetRegisterType(dec_insn.vA,
- reg_types_.FromCat1Const(static_cast<int32_t>(dec_insn.vB << 28) >> 28, true));
+ case Instruction::CONST_4: {
+ int32_t val = static_cast<int32_t>(inst->VRegB_11n() << 28) >> 28;
+ work_line_->SetRegisterType(inst->VRegA_11n(), reg_types_.FromCat1Const(val, true));
break;
- case Instruction::CONST_16:
- work_line_->SetRegisterType(dec_insn.vA,
- reg_types_.FromCat1Const(static_cast<int16_t>(dec_insn.vB), true));
+ }
+ case Instruction::CONST_16: {
+ int16_t val = static_cast<int16_t>(inst->VRegB_21s());
+ work_line_->SetRegisterType(inst->VRegA_21s(), reg_types_.FromCat1Const(val, true));
break;
+ }
case Instruction::CONST:
- work_line_->SetRegisterType(dec_insn.vA, reg_types_.FromCat1Const(dec_insn.vB, true));
+ work_line_->SetRegisterType(inst->VRegA_31i(),
+ reg_types_.FromCat1Const(inst->VRegB_31i(), true));
break;
case Instruction::CONST_HIGH16:
- work_line_->SetRegisterType(dec_insn.vA,
- reg_types_.FromCat1Const(dec_insn.vB << 16, true));
+ work_line_->SetRegisterType(inst->VRegA_21h(),
+ reg_types_.FromCat1Const(inst->VRegB_21h() << 16, true));
break;
/* could be long or double; resolved upon use */
case Instruction::CONST_WIDE_16: {
- int64_t val = static_cast<int16_t>(dec_insn.vB);
+ int64_t val = static_cast<int16_t>(inst->VRegB_21s());
const RegType& lo = reg_types_.FromCat2ConstLo(static_cast<int32_t>(val), true);
const RegType& hi = reg_types_.FromCat2ConstHi(static_cast<int32_t>(val >> 32), true);
- work_line_->SetRegisterTypeWide(dec_insn.vA, lo, hi);
+ work_line_->SetRegisterTypeWide(inst->VRegA_21s(), lo, hi);
break;
}
case Instruction::CONST_WIDE_32: {
- int64_t val = static_cast<int32_t>(dec_insn.vB);
+ int64_t val = static_cast<int32_t>(inst->VRegB_31i());
const RegType& lo = reg_types_.FromCat2ConstLo(static_cast<int32_t>(val), true);
const RegType& hi = reg_types_.FromCat2ConstHi(static_cast<int32_t>(val >> 32), true);
- work_line_->SetRegisterTypeWide(dec_insn.vA, lo, hi);
+ work_line_->SetRegisterTypeWide(inst->VRegA_31i(), lo, hi);
break;
}
case Instruction::CONST_WIDE: {
- int64_t val = dec_insn.vB_wide;
+ int64_t val = inst->VRegB_51l();
const RegType& lo = reg_types_.FromCat2ConstLo(static_cast<int32_t>(val), true);
const RegType& hi = reg_types_.FromCat2ConstHi(static_cast<int32_t>(val >> 32), true);
- work_line_->SetRegisterTypeWide(dec_insn.vA, lo, hi);
+ work_line_->SetRegisterTypeWide(inst->VRegA_51l(), lo, hi);
break;
}
case Instruction::CONST_WIDE_HIGH16: {
- int64_t val = static_cast<uint64_t>(dec_insn.vB) << 48;
+ int64_t val = static_cast<uint64_t>(inst->VRegB_21h()) << 48;
const RegType& lo = reg_types_.FromCat2ConstLo(static_cast<int32_t>(val), true);
const RegType& hi = reg_types_.FromCat2ConstHi(static_cast<int32_t>(val >> 32), true);
- work_line_->SetRegisterTypeWide(dec_insn.vA, lo, hi);
+ work_line_->SetRegisterTypeWide(inst->VRegA_21h(), lo, hi);
break;
}
case Instruction::CONST_STRING:
+ work_line_->SetRegisterType(inst->VRegA_21c(), reg_types_.JavaLangString());
+ break;
case Instruction::CONST_STRING_JUMBO:
- work_line_->SetRegisterType(dec_insn.vA, reg_types_.JavaLangString());
+ work_line_->SetRegisterType(inst->VRegA_31c(), reg_types_.JavaLangString());
break;
case Instruction::CONST_CLASS: {
// Get type from instruction if unresolved then we need an access check
// TODO: check Compiler::CanAccessTypeWithoutChecks returns false when res_type is unresolved
- const RegType& res_type = ResolveClassAndCheckAccess(dec_insn.vB);
+ const RegType& res_type = ResolveClassAndCheckAccess(inst->VRegB_21c());
// Register holds class, ie its type is class, on error it will hold Conflict.
- work_line_->SetRegisterType(dec_insn.vA,
+ work_line_->SetRegisterType(inst->VRegA_21c(),
res_type.IsConflict() ? res_type
: reg_types_.JavaLangClass(true));
break;
}
case Instruction::MONITOR_ENTER:
- work_line_->PushMonitor(dec_insn.vA, work_insn_idx_);
+ work_line_->PushMonitor(inst->VRegA_11x(), work_insn_idx_);
break;
case Instruction::MONITOR_EXIT:
/*
@@ -1515,7 +1612,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
* "live" so we still need to check it.
*/
opcode_flags &= ~Instruction::kThrow;
- work_line_->PopMonitor(dec_insn.vA);
+ work_line_->PopMonitor(inst->VRegA_11x());
break;
case Instruction::CHECK_CAST:
@@ -1527,45 +1624,53 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
* If it fails, an exception is thrown, which we deal with later by ignoring the update to
* dec_insn.vA when branching to a handler.
*/
- bool is_checkcast = dec_insn.opcode == Instruction::CHECK_CAST;
- const RegType& res_type =
- ResolveClassAndCheckAccess(is_checkcast ? dec_insn.vB : dec_insn.vC);
+ const bool is_checkcast = (inst->Opcode() == Instruction::CHECK_CAST);
+ const uint32_t type_idx = (is_checkcast) ? inst->VRegB_21c() : inst->VRegC_22c();
+ const RegType& res_type = ResolveClassAndCheckAccess(type_idx);
if (res_type.IsConflict()) {
DCHECK_NE(failures_.size(), 0U);
if (!is_checkcast) {
- work_line_->SetRegisterType(dec_insn.vA, reg_types_.Boolean());
+ work_line_->SetRegisterType(inst->VRegA_22c(), reg_types_.Boolean());
}
break; // bad class
}
// TODO: check Compiler::CanAccessTypeWithoutChecks returns false when res_type is unresolved
- const RegType& orig_type =
- work_line_->GetRegisterType(is_checkcast ? dec_insn.vA : dec_insn.vB);
+ uint32_t orig_type_reg = (is_checkcast) ? inst->VRegA_21c() : inst->VRegB_22c();
+ const RegType& orig_type = work_line_->GetRegisterType(orig_type_reg);
if (!res_type.IsNonZeroReferenceTypes()) {
- Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "check-cast on unexpected class " << res_type;
+ if (is_checkcast) {
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "check-cast on unexpected class " << res_type;
+ } else {
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "instance-of on unexpected class " << res_type;
+ }
} else if (!orig_type.IsReferenceTypes()) {
- Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "check-cast on non-reference in v" << dec_insn.vA;
+ if (is_checkcast) {
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "check-cast on non-reference in v" << orig_type_reg;
+ } else {
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "instance-of on non-reference in v" << orig_type_reg;
+ }
} else {
if (is_checkcast) {
- work_line_->SetRegisterType(dec_insn.vA, res_type);
+ work_line_->SetRegisterType(inst->VRegA_21c(), res_type);
} else {
- work_line_->SetRegisterType(dec_insn.vA, reg_types_.Boolean());
+ work_line_->SetRegisterType(inst->VRegA_22c(), reg_types_.Boolean());
}
}
break;
}
case Instruction::ARRAY_LENGTH: {
- const RegType& res_type = work_line_->GetRegisterType(dec_insn.vB);
+ const RegType& res_type = work_line_->GetRegisterType(inst->VRegB_12x());
if (res_type.IsReferenceTypes()) {
if (!res_type.IsArrayTypes() && !res_type.IsZero()) { // ie not an array or null
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "array-length on non-array " << res_type;
} else {
- work_line_->SetRegisterType(dec_insn.vA, reg_types_.Integer());
+ work_line_->SetRegisterType(inst->VRegA_12x(), reg_types_.Integer());
}
}
break;
}
case Instruction::NEW_INSTANCE: {
- const RegType& res_type = ResolveClassAndCheckAccess(dec_insn.vB);
+ const RegType& res_type = ResolveClassAndCheckAccess(inst->VRegB_21c());
if (res_type.IsConflict()) {
DCHECK_NE(failures_.size(), 0U);
break; // bad class
@@ -1582,55 +1687,55 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
// initialized must be marked invalid.
work_line_->MarkUninitRefsAsInvalid(uninit_type);
// add the new uninitialized reference to the register state
- work_line_->SetRegisterType(dec_insn.vA, uninit_type);
+ work_line_->SetRegisterType(inst->VRegA_21c(), uninit_type);
break;
}
case Instruction::NEW_ARRAY:
- VerifyNewArray(dec_insn, false, false);
+ VerifyNewArray(inst, false, false);
break;
case Instruction::FILLED_NEW_ARRAY:
- VerifyNewArray(dec_insn, true, false);
+ VerifyNewArray(inst, true, false);
just_set_result = true; // Filled new array sets result register
break;
case Instruction::FILLED_NEW_ARRAY_RANGE:
- VerifyNewArray(dec_insn, true, true);
+ VerifyNewArray(inst, true, true);
just_set_result = true; // Filled new array range sets result register
break;
case Instruction::CMPL_FLOAT:
case Instruction::CMPG_FLOAT:
- if (!work_line_->VerifyRegisterType(dec_insn.vB, reg_types_.Float())) {
+ if (!work_line_->VerifyRegisterType(inst->VRegB_23x(), reg_types_.Float())) {
break;
}
- if (!work_line_->VerifyRegisterType(dec_insn.vC, reg_types_.Float())) {
+ if (!work_line_->VerifyRegisterType(inst->VRegC_23x(), reg_types_.Float())) {
break;
}
- work_line_->SetRegisterType(dec_insn.vA, reg_types_.Integer());
+ work_line_->SetRegisterType(inst->VRegA_23x(), reg_types_.Integer());
break;
case Instruction::CMPL_DOUBLE:
case Instruction::CMPG_DOUBLE:
- if (!work_line_->VerifyRegisterTypeWide(dec_insn.vB, reg_types_.DoubleLo(),
+ if (!work_line_->VerifyRegisterTypeWide(inst->VRegB_23x(), reg_types_.DoubleLo(),
reg_types_.DoubleHi())) {
break;
}
- if (!work_line_->VerifyRegisterTypeWide(dec_insn.vC, reg_types_.DoubleLo(),
+ if (!work_line_->VerifyRegisterTypeWide(inst->VRegC_23x(), reg_types_.DoubleLo(),
reg_types_.DoubleHi())) {
break;
}
- work_line_->SetRegisterType(dec_insn.vA, reg_types_.Integer());
+ work_line_->SetRegisterType(inst->VRegA_23x(), reg_types_.Integer());
break;
case Instruction::CMP_LONG:
- if (!work_line_->VerifyRegisterTypeWide(dec_insn.vB, reg_types_.LongLo(),
+ if (!work_line_->VerifyRegisterTypeWide(inst->VRegB_23x(), reg_types_.LongLo(),
reg_types_.LongHi())) {
break;
}
- if (!work_line_->VerifyRegisterTypeWide(dec_insn.vC, reg_types_.LongLo(),
+ if (!work_line_->VerifyRegisterTypeWide(inst->VRegC_23x(), reg_types_.LongLo(),
reg_types_.LongHi())) {
break;
}
- work_line_->SetRegisterType(dec_insn.vA, reg_types_.Integer());
+ work_line_->SetRegisterType(inst->VRegA_23x(), reg_types_.Integer());
break;
case Instruction::THROW: {
- const RegType& res_type = work_line_->GetRegisterType(dec_insn.vA);
+ const RegType& res_type = work_line_->GetRegisterType(inst->VRegA_11x());
if (!reg_types_.JavaLangThrowable(false).IsAssignableFrom(res_type)) {
Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "thrown class " << res_type << " not instanceof Throwable";
}
@@ -1645,12 +1750,12 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
case Instruction::PACKED_SWITCH:
case Instruction::SPARSE_SWITCH:
/* verify that vAA is an integer, or can be converted to one */
- work_line_->VerifyRegisterType(dec_insn.vA, reg_types_.Integer());
+ work_line_->VerifyRegisterType(inst->VRegA_31t(), reg_types_.Integer());
break;
case Instruction::FILL_ARRAY_DATA: {
/* Similar to the verification done for APUT */
- const RegType& array_type = work_line_->GetRegisterType(dec_insn.vA);
+ const RegType& array_type = work_line_->GetRegisterType(inst->VRegA_31t());
/* array_type can be null if the reg type is Zero */
if (!array_type.IsZero()) {
if (!array_type.IsArrayTypes()) {
@@ -1683,8 +1788,8 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
}
case Instruction::IF_EQ:
case Instruction::IF_NE: {
- const RegType& reg_type1 = work_line_->GetRegisterType(dec_insn.vA);
- const RegType& reg_type2 = work_line_->GetRegisterType(dec_insn.vB);
+ const RegType& reg_type1 = work_line_->GetRegisterType(inst->VRegA_22t());
+ const RegType& reg_type2 = work_line_->GetRegisterType(inst->VRegB_22t());
bool mismatch = false;
if (reg_type1.IsZero()) { // zero then integral or reference expected
mismatch = !reg_type2.IsReferenceTypes() && !reg_type2.IsIntegralTypes();
@@ -1703,8 +1808,8 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
case Instruction::IF_GE:
case Instruction::IF_GT:
case Instruction::IF_LE: {
- const RegType& reg_type1 = work_line_->GetRegisterType(dec_insn.vA);
- const RegType& reg_type2 = work_line_->GetRegisterType(dec_insn.vB);
+ const RegType& reg_type1 = work_line_->GetRegisterType(inst->VRegA_22t());
+ const RegType& reg_type2 = work_line_->GetRegisterType(inst->VRegB_22t());
if (!reg_type1.IsIntegralTypes() || !reg_type2.IsIntegralTypes()) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "args to 'if' (" << reg_type1 << ","
<< reg_type2 << ") must be integral";
@@ -1713,17 +1818,94 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
}
case Instruction::IF_EQZ:
case Instruction::IF_NEZ: {
- const RegType& reg_type = work_line_->GetRegisterType(dec_insn.vA);
+ const RegType& reg_type = work_line_->GetRegisterType(inst->VRegA_21t());
if (!reg_type.IsReferenceTypes() && !reg_type.IsIntegralTypes()) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "type " << reg_type << " unexpected as arg to if-eqz/if-nez";
}
+
+ // Find previous instruction - its existence is a precondition to peephole optimization.
+ uint32_t instance_of_idx = 0;
+ if (0 != work_insn_idx_) {
+ instance_of_idx = work_insn_idx_ - 1;
+ while(0 != instance_of_idx && !insn_flags_[instance_of_idx].IsOpcode()) {
+ instance_of_idx--;
+ }
+ CHECK(insn_flags_[instance_of_idx].IsOpcode());
+ } else {
+ break;
+ }
+
+ const Instruction* instance_of_inst = Instruction::At(code_item_->insns_ + instance_of_idx);
+
+ /* Check for peep-hole pattern of:
+ * ...;
+ * instance-of vX, vY, T;
+ * ifXXX vX, label ;
+ * ...;
+ * label:
+ * ...;
+ * and sharpen the type of vY to be type T.
+ * Note, this pattern can't be if:
+ * - if there are other branches to this branch,
+ * - when vX == vY.
+ */
+ if (!CurrentInsnFlags()->IsBranchTarget() &&
+ (Instruction::INSTANCE_OF == instance_of_inst->Opcode()) &&
+ (inst->VRegA_21t() == instance_of_inst->VRegA_22c()) &&
+ (instance_of_inst->VRegA_22c() != instance_of_inst->VRegB_22c())) {
+ // Check that the we are not attempting conversion to interface types,
+ // which is not done because of the multiple inheritance implications.
+ const RegType& cast_type = ResolveClassAndCheckAccess(instance_of_inst->VRegC_22c());
+
+ if(!cast_type.IsUnresolvedTypes() && !cast_type.GetClass()->IsInterface()) {
+ RegisterLine* update_line = new RegisterLine(code_item_->registers_size_, this);
+ if (inst->Opcode() == Instruction::IF_EQZ) {
+ fallthrough_line.reset(update_line);
+ } else {
+ branch_line.reset(update_line);
+ }
+ update_line->CopyFromLine(work_line_.get());
+ update_line->SetRegisterType(instance_of_inst->VRegB_22c(), cast_type);
+ if (!insn_flags_[instance_of_idx].IsBranchTarget() && 0 != instance_of_idx) {
+ // See if instance-of was preceded by a move-object operation, common due to the small
+ // register encoding space of instance-of, and propagate type information to the source
+ // of the move-object.
+ uint32_t move_idx = instance_of_idx - 1;
+ while(0 != move_idx && !insn_flags_[move_idx].IsOpcode()) {
+ move_idx--;
+ }
+ CHECK(insn_flags_[move_idx].IsOpcode());
+ const Instruction* move_inst = Instruction::At(code_item_->insns_ + move_idx);
+ switch (move_inst->Opcode()) {
+ case Instruction::MOVE_OBJECT:
+ if (move_inst->VRegA_12x() == instance_of_inst->VRegB_22c()) {
+ update_line->SetRegisterType(move_inst->VRegB_12x(), cast_type);
+ }
+ break;
+ case Instruction::MOVE_OBJECT_FROM16:
+ if (move_inst->VRegA_22x() == instance_of_inst->VRegB_22c()) {
+ update_line->SetRegisterType(move_inst->VRegB_22x(), cast_type);
+ }
+ break;
+ case Instruction::MOVE_OBJECT_16:
+ if (move_inst->VRegA_32x() == instance_of_inst->VRegB_22c()) {
+ update_line->SetRegisterType(move_inst->VRegB_32x(), cast_type);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+
break;
}
case Instruction::IF_LTZ:
case Instruction::IF_GEZ:
case Instruction::IF_GTZ:
case Instruction::IF_LEZ: {
- const RegType& reg_type = work_line_->GetRegisterType(dec_insn.vA);
+ const RegType& reg_type = work_line_->GetRegisterType(inst->VRegA_21t());
if (!reg_type.IsIntegralTypes()) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "type " << reg_type
<< " unexpected as arg to if-ltz/if-gez/if-gtz/if-lez";
@@ -1731,150 +1913,150 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
break;
}
case Instruction::AGET_BOOLEAN:
- VerifyAGet(dec_insn, reg_types_.Boolean(), true);
+ VerifyAGet(inst, reg_types_.Boolean(), true);
break;
case Instruction::AGET_BYTE:
- VerifyAGet(dec_insn, reg_types_.Byte(), true);
+ VerifyAGet(inst, reg_types_.Byte(), true);
break;
case Instruction::AGET_CHAR:
- VerifyAGet(dec_insn, reg_types_.Char(), true);
+ VerifyAGet(inst, reg_types_.Char(), true);
break;
case Instruction::AGET_SHORT:
- VerifyAGet(dec_insn, reg_types_.Short(), true);
+ VerifyAGet(inst, reg_types_.Short(), true);
break;
case Instruction::AGET:
- VerifyAGet(dec_insn, reg_types_.Integer(), true);
+ VerifyAGet(inst, reg_types_.Integer(), true);
break;
case Instruction::AGET_WIDE:
- VerifyAGet(dec_insn, reg_types_.LongLo(), true);
+ VerifyAGet(inst, reg_types_.LongLo(), true);
break;
case Instruction::AGET_OBJECT:
- VerifyAGet(dec_insn, reg_types_.JavaLangObject(false), false);
+ VerifyAGet(inst, reg_types_.JavaLangObject(false), false);
break;
case Instruction::APUT_BOOLEAN:
- VerifyAPut(dec_insn, reg_types_.Boolean(), true);
+ VerifyAPut(inst, reg_types_.Boolean(), true);
break;
case Instruction::APUT_BYTE:
- VerifyAPut(dec_insn, reg_types_.Byte(), true);
+ VerifyAPut(inst, reg_types_.Byte(), true);
break;
case Instruction::APUT_CHAR:
- VerifyAPut(dec_insn, reg_types_.Char(), true);
+ VerifyAPut(inst, reg_types_.Char(), true);
break;
case Instruction::APUT_SHORT:
- VerifyAPut(dec_insn, reg_types_.Short(), true);
+ VerifyAPut(inst, reg_types_.Short(), true);
break;
case Instruction::APUT:
- VerifyAPut(dec_insn, reg_types_.Integer(), true);
+ VerifyAPut(inst, reg_types_.Integer(), true);
break;
case Instruction::APUT_WIDE:
- VerifyAPut(dec_insn, reg_types_.LongLo(), true);
+ VerifyAPut(inst, reg_types_.LongLo(), true);
break;
case Instruction::APUT_OBJECT:
- VerifyAPut(dec_insn, reg_types_.JavaLangObject(false), false);
+ VerifyAPut(inst, reg_types_.JavaLangObject(false), false);
break;
case Instruction::IGET_BOOLEAN:
- VerifyISGet(dec_insn, reg_types_.Boolean(), true, false);
+ VerifyISGet(inst, reg_types_.Boolean(), true, false);
break;
case Instruction::IGET_BYTE:
- VerifyISGet(dec_insn, reg_types_.Byte(), true, false);
+ VerifyISGet(inst, reg_types_.Byte(), true, false);
break;
case Instruction::IGET_CHAR:
- VerifyISGet(dec_insn, reg_types_.Char(), true, false);
+ VerifyISGet(inst, reg_types_.Char(), true, false);
break;
case Instruction::IGET_SHORT:
- VerifyISGet(dec_insn, reg_types_.Short(), true, false);
+ VerifyISGet(inst, reg_types_.Short(), true, false);
break;
case Instruction::IGET:
- VerifyISGet(dec_insn, reg_types_.Integer(), true, false);
+ VerifyISGet(inst, reg_types_.Integer(), true, false);
break;
case Instruction::IGET_WIDE:
- VerifyISGet(dec_insn, reg_types_.LongLo(), true, false);
+ VerifyISGet(inst, reg_types_.LongLo(), true, false);
break;
case Instruction::IGET_OBJECT:
- VerifyISGet(dec_insn, reg_types_.JavaLangObject(false), false, false);
+ VerifyISGet(inst, reg_types_.JavaLangObject(false), false, false);
break;
case Instruction::IPUT_BOOLEAN:
- VerifyISPut(dec_insn, reg_types_.Boolean(), true, false);
+ VerifyISPut(inst, reg_types_.Boolean(), true, false);
break;
case Instruction::IPUT_BYTE:
- VerifyISPut(dec_insn, reg_types_.Byte(), true, false);
+ VerifyISPut(inst, reg_types_.Byte(), true, false);
break;
case Instruction::IPUT_CHAR:
- VerifyISPut(dec_insn, reg_types_.Char(), true, false);
+ VerifyISPut(inst, reg_types_.Char(), true, false);
break;
case Instruction::IPUT_SHORT:
- VerifyISPut(dec_insn, reg_types_.Short(), true, false);
+ VerifyISPut(inst, reg_types_.Short(), true, false);
break;
case Instruction::IPUT:
- VerifyISPut(dec_insn, reg_types_.Integer(), true, false);
+ VerifyISPut(inst, reg_types_.Integer(), true, false);
break;
case Instruction::IPUT_WIDE:
- VerifyISPut(dec_insn, reg_types_.LongLo(), true, false);
+ VerifyISPut(inst, reg_types_.LongLo(), true, false);
break;
case Instruction::IPUT_OBJECT:
- VerifyISPut(dec_insn, reg_types_.JavaLangObject(false), false, false);
+ VerifyISPut(inst, reg_types_.JavaLangObject(false), false, false);
break;
case Instruction::SGET_BOOLEAN:
- VerifyISGet(dec_insn, reg_types_.Boolean(), true, true);
+ VerifyISGet(inst, reg_types_.Boolean(), true, true);
break;
case Instruction::SGET_BYTE:
- VerifyISGet(dec_insn, reg_types_.Byte(), true, true);
+ VerifyISGet(inst, reg_types_.Byte(), true, true);
break;
case Instruction::SGET_CHAR:
- VerifyISGet(dec_insn, reg_types_.Char(), true, true);
+ VerifyISGet(inst, reg_types_.Char(), true, true);
break;
case Instruction::SGET_SHORT:
- VerifyISGet(dec_insn, reg_types_.Short(), true, true);
+ VerifyISGet(inst, reg_types_.Short(), true, true);
break;
case Instruction::SGET:
- VerifyISGet(dec_insn, reg_types_.Integer(), true, true);
+ VerifyISGet(inst, reg_types_.Integer(), true, true);
break;
case Instruction::SGET_WIDE:
- VerifyISGet(dec_insn, reg_types_.LongLo(), true, true);
+ VerifyISGet(inst, reg_types_.LongLo(), true, true);
break;
case Instruction::SGET_OBJECT:
- VerifyISGet(dec_insn, reg_types_.JavaLangObject(false), false, true);
+ VerifyISGet(inst, reg_types_.JavaLangObject(false), false, true);
break;
case Instruction::SPUT_BOOLEAN:
- VerifyISPut(dec_insn, reg_types_.Boolean(), true, true);
+ VerifyISPut(inst, reg_types_.Boolean(), true, true);
break;
case Instruction::SPUT_BYTE:
- VerifyISPut(dec_insn, reg_types_.Byte(), true, true);
+ VerifyISPut(inst, reg_types_.Byte(), true, true);
break;
case Instruction::SPUT_CHAR:
- VerifyISPut(dec_insn, reg_types_.Char(), true, true);
+ VerifyISPut(inst, reg_types_.Char(), true, true);
break;
case Instruction::SPUT_SHORT:
- VerifyISPut(dec_insn, reg_types_.Short(), true, true);
+ VerifyISPut(inst, reg_types_.Short(), true, true);
break;
case Instruction::SPUT:
- VerifyISPut(dec_insn, reg_types_.Integer(), true, true);
+ VerifyISPut(inst, reg_types_.Integer(), true, true);
break;
case Instruction::SPUT_WIDE:
- VerifyISPut(dec_insn, reg_types_.LongLo(), true, true);
+ VerifyISPut(inst, reg_types_.LongLo(), true, true);
break;
case Instruction::SPUT_OBJECT:
- VerifyISPut(dec_insn, reg_types_.JavaLangObject(false), false, true);
+ VerifyISPut(inst, reg_types_.JavaLangObject(false), false, true);
break;
case Instruction::INVOKE_VIRTUAL:
case Instruction::INVOKE_VIRTUAL_RANGE:
case Instruction::INVOKE_SUPER:
case Instruction::INVOKE_SUPER_RANGE: {
- bool is_range = (dec_insn.opcode == Instruction::INVOKE_VIRTUAL_RANGE ||
- dec_insn.opcode == Instruction::INVOKE_SUPER_RANGE);
- bool is_super = (dec_insn.opcode == Instruction::INVOKE_SUPER ||
- dec_insn.opcode == Instruction::INVOKE_SUPER_RANGE);
- mirror::AbstractMethod* called_method = VerifyInvocationArgs(dec_insn, METHOD_VIRTUAL,
+ bool is_range = (inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE ||
+ inst->Opcode() == Instruction::INVOKE_SUPER_RANGE);
+ bool is_super = (inst->Opcode() == Instruction::INVOKE_SUPER ||
+ inst->Opcode() == Instruction::INVOKE_SUPER_RANGE);
+ mirror::AbstractMethod* called_method = VerifyInvocationArgs(inst, METHOD_VIRTUAL,
is_range, is_super);
const char* descriptor;
if (called_method == NULL) {
- uint32_t method_idx = dec_insn.vB;
+ uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx);
uint32_t return_type_idx = dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_;
descriptor = dex_file_->StringByTypeIdx(return_type_idx);
@@ -1892,13 +2074,13 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
}
case Instruction::INVOKE_DIRECT:
case Instruction::INVOKE_DIRECT_RANGE: {
- bool is_range = (dec_insn.opcode == Instruction::INVOKE_DIRECT_RANGE);
- mirror::AbstractMethod* called_method = VerifyInvocationArgs(dec_insn, METHOD_DIRECT,
+ bool is_range = (inst->Opcode() == Instruction::INVOKE_DIRECT_RANGE);
+ mirror::AbstractMethod* called_method = VerifyInvocationArgs(inst, METHOD_DIRECT,
is_range, false);
const char* return_type_descriptor;
bool is_constructor;
if (called_method == NULL) {
- uint32_t method_idx = dec_insn.vB;
+ uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx);
is_constructor = StringPiece(dex_file_->GetMethodName(method_id)) == "<init>";
uint32_t return_type_idx = dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_;
@@ -1915,7 +2097,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
* 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).
*/
- const RegType& this_type = work_line_->GetInvocationThis(dec_insn);
+ const RegType& this_type = work_line_->GetInvocationThis(inst, is_range);
if (this_type.IsConflict()) // failure.
break;
@@ -1959,11 +2141,11 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
}
case Instruction::INVOKE_STATIC:
case Instruction::INVOKE_STATIC_RANGE: {
- bool is_range = (dec_insn.opcode == Instruction::INVOKE_STATIC_RANGE);
- mirror::AbstractMethod* called_method = VerifyInvocationArgs(dec_insn, METHOD_STATIC, is_range, false);
+ bool is_range = (inst->Opcode() == Instruction::INVOKE_STATIC_RANGE);
+ mirror::AbstractMethod* called_method = VerifyInvocationArgs(inst, METHOD_STATIC, is_range, false);
const char* descriptor;
if (called_method == NULL) {
- uint32_t method_idx = dec_insn.vB;
+ uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx);
uint32_t return_type_idx = dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_;
descriptor = dex_file_->StringByTypeIdx(return_type_idx);
@@ -1981,8 +2163,8 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
break;
case Instruction::INVOKE_INTERFACE:
case Instruction::INVOKE_INTERFACE_RANGE: {
- bool is_range = (dec_insn.opcode == Instruction::INVOKE_INTERFACE_RANGE);
- mirror::AbstractMethod* abs_method = VerifyInvocationArgs(dec_insn, METHOD_INTERFACE, is_range, false);
+ bool is_range = (inst->Opcode() == Instruction::INVOKE_INTERFACE_RANGE);
+ mirror::AbstractMethod* abs_method = VerifyInvocationArgs(inst, METHOD_INTERFACE, is_range, false);
if (abs_method != NULL) {
mirror::Class* called_interface = abs_method->GetDeclaringClass();
if (!called_interface->IsInterface() && !called_interface->IsObjectClass()) {
@@ -1994,7 +2176,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
/* Get the type of the "this" arg, which should either be a sub-interface of called
* interface or Object (see comments in RegType::JoinClass).
*/
- const RegType& this_type = work_line_->GetInvocationThis(dec_insn);
+ const RegType& this_type = work_line_->GetInvocationThis(inst, is_range);
if (this_type.IsZero()) {
/* null pointer always passes (and always fails at runtime) */
} else {
@@ -2017,7 +2199,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
*/
const char* descriptor;
if (abs_method == NULL) {
- uint32_t method_idx = dec_insn.vB;
+ uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx);
uint32_t return_type_idx = dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_;
descriptor = dex_file_->StringByTypeIdx(return_type_idx);
@@ -2035,74 +2217,74 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
}
case Instruction::NEG_INT:
case Instruction::NOT_INT:
- work_line_->CheckUnaryOp(dec_insn, reg_types_.Integer(), reg_types_.Integer());
+ work_line_->CheckUnaryOp(inst, reg_types_.Integer(), reg_types_.Integer());
break;
case Instruction::NEG_LONG:
case Instruction::NOT_LONG:
- work_line_->CheckUnaryOpWide(dec_insn, reg_types_.LongLo(), reg_types_.LongHi(),
+ work_line_->CheckUnaryOpWide(inst, reg_types_.LongLo(), reg_types_.LongHi(),
reg_types_.LongLo(), reg_types_.LongHi());
break;
case Instruction::NEG_FLOAT:
- work_line_->CheckUnaryOp(dec_insn, reg_types_.Float(), reg_types_.Float());
+ work_line_->CheckUnaryOp(inst, reg_types_.Float(), reg_types_.Float());
break;
case Instruction::NEG_DOUBLE:
- work_line_->CheckUnaryOpWide(dec_insn, reg_types_.DoubleLo(), reg_types_.DoubleHi(),
+ work_line_->CheckUnaryOpWide(inst, reg_types_.DoubleLo(), reg_types_.DoubleHi(),
reg_types_.DoubleLo(), reg_types_.DoubleHi());
break;
case Instruction::INT_TO_LONG:
- work_line_->CheckUnaryOpToWide(dec_insn, reg_types_.LongLo(), reg_types_.LongHi(),
+ work_line_->CheckUnaryOpToWide(inst, reg_types_.LongLo(), reg_types_.LongHi(),
reg_types_.Integer());
break;
case Instruction::INT_TO_FLOAT:
- work_line_->CheckUnaryOp(dec_insn, reg_types_.Float(), reg_types_.Integer());
+ work_line_->CheckUnaryOp(inst, reg_types_.Float(), reg_types_.Integer());
break;
case Instruction::INT_TO_DOUBLE:
- work_line_->CheckUnaryOpToWide(dec_insn, reg_types_.DoubleLo(), reg_types_.DoubleHi(),
+ work_line_->CheckUnaryOpToWide(inst, reg_types_.DoubleLo(), reg_types_.DoubleHi(),
reg_types_.Integer());
break;
case Instruction::LONG_TO_INT:
- work_line_->CheckUnaryOpFromWide(dec_insn, reg_types_.Integer(),
+ work_line_->CheckUnaryOpFromWide(inst, reg_types_.Integer(),
reg_types_.LongLo(), reg_types_.LongHi());
break;
case Instruction::LONG_TO_FLOAT:
- work_line_->CheckUnaryOpFromWide(dec_insn, reg_types_.Float(),
+ work_line_->CheckUnaryOpFromWide(inst, reg_types_.Float(),
reg_types_.LongLo(), reg_types_.LongHi());
break;
case Instruction::LONG_TO_DOUBLE:
- work_line_->CheckUnaryOpWide(dec_insn, reg_types_.DoubleLo(), reg_types_.DoubleHi(),
+ work_line_->CheckUnaryOpWide(inst, reg_types_.DoubleLo(), reg_types_.DoubleHi(),
reg_types_.LongLo(), reg_types_.LongHi());
break;
case Instruction::FLOAT_TO_INT:
- work_line_->CheckUnaryOp(dec_insn, reg_types_.Integer(), reg_types_.Float());
+ work_line_->CheckUnaryOp(inst, reg_types_.Integer(), reg_types_.Float());
break;
case Instruction::FLOAT_TO_LONG:
- work_line_->CheckUnaryOpToWide(dec_insn, reg_types_.LongLo(), reg_types_.LongHi(),
+ work_line_->CheckUnaryOpToWide(inst, reg_types_.LongLo(), reg_types_.LongHi(),
reg_types_.Float());
break;
case Instruction::FLOAT_TO_DOUBLE:
- work_line_->CheckUnaryOpToWide(dec_insn, reg_types_.DoubleLo(), reg_types_.DoubleHi(),
+ work_line_->CheckUnaryOpToWide(inst, reg_types_.DoubleLo(), reg_types_.DoubleHi(),
reg_types_.Float());
break;
case Instruction::DOUBLE_TO_INT:
- work_line_->CheckUnaryOpFromWide(dec_insn, reg_types_.Integer(),
+ work_line_->CheckUnaryOpFromWide(inst, reg_types_.Integer(),
reg_types_.DoubleLo(), reg_types_.DoubleHi());
break;
case Instruction::DOUBLE_TO_LONG:
- work_line_->CheckUnaryOpWide(dec_insn, reg_types_.LongLo(), reg_types_.LongHi(),
+ work_line_->CheckUnaryOpWide(inst, reg_types_.LongLo(), reg_types_.LongHi(),
reg_types_.DoubleLo(), reg_types_.DoubleHi());
break;
case Instruction::DOUBLE_TO_FLOAT:
- work_line_->CheckUnaryOpFromWide(dec_insn, reg_types_.Float(),
+ work_line_->CheckUnaryOpFromWide(inst, reg_types_.Float(),
reg_types_.DoubleLo(), reg_types_.DoubleHi());
break;
case Instruction::INT_TO_BYTE:
- work_line_->CheckUnaryOp(dec_insn, reg_types_.Byte(), reg_types_.Integer());
+ work_line_->CheckUnaryOp(inst, reg_types_.Byte(), reg_types_.Integer());
break;
case Instruction::INT_TO_CHAR:
- work_line_->CheckUnaryOp(dec_insn, reg_types_.Char(), reg_types_.Integer());
+ work_line_->CheckUnaryOp(inst, reg_types_.Char(), reg_types_.Integer());
break;
case Instruction::INT_TO_SHORT:
- work_line_->CheckUnaryOp(dec_insn, reg_types_.Short(), reg_types_.Integer());
+ work_line_->CheckUnaryOp(inst, reg_types_.Short(), reg_types_.Integer());
break;
case Instruction::ADD_INT:
@@ -2113,13 +2295,13 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
case Instruction::SHL_INT:
case Instruction::SHR_INT:
case Instruction::USHR_INT:
- work_line_->CheckBinaryOp(dec_insn, reg_types_.Integer(), reg_types_.Integer(),
+ work_line_->CheckBinaryOp(inst, reg_types_.Integer(), reg_types_.Integer(),
reg_types_.Integer(), false);
break;
case Instruction::AND_INT:
case Instruction::OR_INT:
case Instruction::XOR_INT:
- work_line_->CheckBinaryOp(dec_insn, reg_types_.Integer(), reg_types_.Integer(),
+ work_line_->CheckBinaryOp(inst, reg_types_.Integer(), reg_types_.Integer(),
reg_types_.Integer(), true);
break;
case Instruction::ADD_LONG:
@@ -2130,7 +2312,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
case Instruction::AND_LONG:
case Instruction::OR_LONG:
case Instruction::XOR_LONG:
- work_line_->CheckBinaryOpWide(dec_insn, reg_types_.LongLo(), reg_types_.LongHi(),
+ work_line_->CheckBinaryOpWide(inst, reg_types_.LongLo(), reg_types_.LongHi(),
reg_types_.LongLo(), reg_types_.LongHi(),
reg_types_.LongLo(), reg_types_.LongHi());
break;
@@ -2138,7 +2320,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
case Instruction::SHR_LONG:
case Instruction::USHR_LONG:
/* shift distance is Int, making these different from other binary operations */
- work_line_->CheckBinaryOpWideShift(dec_insn, reg_types_.LongLo(), reg_types_.LongHi(),
+ work_line_->CheckBinaryOpWideShift(inst, reg_types_.LongLo(), reg_types_.LongHi(),
reg_types_.Integer());
break;
case Instruction::ADD_FLOAT:
@@ -2146,14 +2328,14 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
case Instruction::MUL_FLOAT:
case Instruction::DIV_FLOAT:
case Instruction::REM_FLOAT:
- work_line_->CheckBinaryOp(dec_insn, reg_types_.Float(), reg_types_.Float(), reg_types_.Float(), false);
+ work_line_->CheckBinaryOp(inst, reg_types_.Float(), reg_types_.Float(), reg_types_.Float(), false);
break;
case Instruction::ADD_DOUBLE:
case Instruction::SUB_DOUBLE:
case Instruction::MUL_DOUBLE:
case Instruction::DIV_DOUBLE:
case Instruction::REM_DOUBLE:
- work_line_->CheckBinaryOpWide(dec_insn, reg_types_.DoubleLo(), reg_types_.DoubleHi(),
+ work_line_->CheckBinaryOpWide(inst, reg_types_.DoubleLo(), reg_types_.DoubleHi(),
reg_types_.DoubleLo(), reg_types_.DoubleHi(),
reg_types_.DoubleLo(), reg_types_.DoubleHi());
break;
@@ -2164,15 +2346,15 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
case Instruction::SHL_INT_2ADDR:
case Instruction::SHR_INT_2ADDR:
case Instruction::USHR_INT_2ADDR:
- work_line_->CheckBinaryOp2addr(dec_insn, reg_types_.Integer(), reg_types_.Integer(), reg_types_.Integer(), false);
+ work_line_->CheckBinaryOp2addr(inst, reg_types_.Integer(), reg_types_.Integer(), reg_types_.Integer(), false);
break;
case Instruction::AND_INT_2ADDR:
case Instruction::OR_INT_2ADDR:
case Instruction::XOR_INT_2ADDR:
- work_line_->CheckBinaryOp2addr(dec_insn, reg_types_.Integer(), reg_types_.Integer(), reg_types_.Integer(), true);
+ work_line_->CheckBinaryOp2addr(inst, reg_types_.Integer(), reg_types_.Integer(), reg_types_.Integer(), true);
break;
case Instruction::DIV_INT_2ADDR:
- work_line_->CheckBinaryOp2addr(dec_insn, reg_types_.Integer(), reg_types_.Integer(), reg_types_.Integer(), false);
+ work_line_->CheckBinaryOp2addr(inst, reg_types_.Integer(), reg_types_.Integer(), reg_types_.Integer(), false);
break;
case Instruction::ADD_LONG_2ADDR:
case Instruction::SUB_LONG_2ADDR:
@@ -2182,14 +2364,14 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
case Instruction::AND_LONG_2ADDR:
case Instruction::OR_LONG_2ADDR:
case Instruction::XOR_LONG_2ADDR:
- work_line_->CheckBinaryOp2addrWide(dec_insn, reg_types_.LongLo(), reg_types_.LongHi(),
+ work_line_->CheckBinaryOp2addrWide(inst, reg_types_.LongLo(), reg_types_.LongHi(),
reg_types_.LongLo(), reg_types_.LongHi(),
reg_types_.LongLo(), reg_types_.LongHi());
break;
case Instruction::SHL_LONG_2ADDR:
case Instruction::SHR_LONG_2ADDR:
case Instruction::USHR_LONG_2ADDR:
- work_line_->CheckBinaryOp2addrWideShift(dec_insn, reg_types_.LongLo(), reg_types_.LongHi(),
+ work_line_->CheckBinaryOp2addrWideShift(inst, reg_types_.LongLo(), reg_types_.LongHi(),
reg_types_.Integer());
break;
case Instruction::ADD_FLOAT_2ADDR:
@@ -2197,14 +2379,14 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
case Instruction::MUL_FLOAT_2ADDR:
case Instruction::DIV_FLOAT_2ADDR:
case Instruction::REM_FLOAT_2ADDR:
- work_line_->CheckBinaryOp2addr(dec_insn, reg_types_.Float(), reg_types_.Float(), reg_types_.Float(), false);
+ work_line_->CheckBinaryOp2addr(inst, reg_types_.Float(), reg_types_.Float(), reg_types_.Float(), false);
break;
case Instruction::ADD_DOUBLE_2ADDR:
case Instruction::SUB_DOUBLE_2ADDR:
case Instruction::MUL_DOUBLE_2ADDR:
case Instruction::DIV_DOUBLE_2ADDR:
case Instruction::REM_DOUBLE_2ADDR:
- work_line_->CheckBinaryOp2addrWide(dec_insn, reg_types_.DoubleLo(), reg_types_.DoubleHi(),
+ work_line_->CheckBinaryOp2addrWide(inst, reg_types_.DoubleLo(), reg_types_.DoubleHi(),
reg_types_.DoubleLo(), reg_types_.DoubleHi(),
reg_types_.DoubleLo(), reg_types_.DoubleHi());
break;
@@ -2213,12 +2395,12 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
case Instruction::MUL_INT_LIT16:
case Instruction::DIV_INT_LIT16:
case Instruction::REM_INT_LIT16:
- work_line_->CheckLiteralOp(dec_insn, reg_types_.Integer(), reg_types_.Integer(), false);
+ work_line_->CheckLiteralOp(inst, reg_types_.Integer(), reg_types_.Integer(), false, true);
break;
case Instruction::AND_INT_LIT16:
case Instruction::OR_INT_LIT16:
case Instruction::XOR_INT_LIT16:
- work_line_->CheckLiteralOp(dec_insn, reg_types_.Integer(), reg_types_.Integer(), true);
+ work_line_->CheckLiteralOp(inst, reg_types_.Integer(), reg_types_.Integer(), true, true);
break;
case Instruction::ADD_INT_LIT8:
case Instruction::RSUB_INT_LIT8:
@@ -2228,18 +2410,71 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
case Instruction::SHL_INT_LIT8:
case Instruction::SHR_INT_LIT8:
case Instruction::USHR_INT_LIT8:
- work_line_->CheckLiteralOp(dec_insn, reg_types_.Integer(), reg_types_.Integer(), false);
+ work_line_->CheckLiteralOp(inst, reg_types_.Integer(), reg_types_.Integer(), false, false);
break;
case Instruction::AND_INT_LIT8:
case Instruction::OR_INT_LIT8:
case Instruction::XOR_INT_LIT8:
- work_line_->CheckLiteralOp(dec_insn, reg_types_.Integer(), reg_types_.Integer(), true);
+ work_line_->CheckLiteralOp(inst, reg_types_.Integer(), reg_types_.Integer(), true, false);
+ break;
+
+ // Special instructions.
+ //
+ // Note: the following instructions encode offsets derived from class linking.
+ // As such they use Class*/Field*/AbstractMethod* as these offsets only have
+ // meaning if the class linking and resolution were successful.
+ case Instruction::IGET_QUICK:
+ VerifyIGetQuick(inst, reg_types_.Integer(), true);
+ break;
+ case Instruction::IGET_WIDE_QUICK:
+ VerifyIGetQuick(inst, reg_types_.LongLo(), true);
+ break;
+ case Instruction::IGET_OBJECT_QUICK:
+ VerifyIGetQuick(inst, reg_types_.JavaLangObject(false), false);
+ break;
+ case Instruction::IPUT_QUICK:
+ VerifyIPutQuick(inst, reg_types_.Integer(), true);
+ break;
+ case Instruction::IPUT_WIDE_QUICK:
+ VerifyIPutQuick(inst, reg_types_.LongLo(), true);
+ break;
+ case Instruction::IPUT_OBJECT_QUICK:
+ VerifyIPutQuick(inst, reg_types_.JavaLangObject(false), false);
+ break;
+ case Instruction::INVOKE_VIRTUAL_QUICK:
+ case Instruction::INVOKE_VIRTUAL_RANGE_QUICK: {
+ bool is_range = (inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE_QUICK);
+ mirror::AbstractMethod* called_method = VerifyInvokeVirtualQuickArgs(inst, is_range);
+ if (called_method != NULL) {
+ const char* descriptor = MethodHelper(called_method).GetReturnTypeDescriptor();
+ const RegType& return_type = reg_types_.FromDescriptor(class_loader_, descriptor, false);
+ if (!return_type.IsLowHalf()) {
+ work_line_->SetResultRegisterType(return_type);
+ } else {
+ work_line_->SetResultRegisterTypeWide(return_type, return_type.HighHalf(&reg_types_));
+ }
+ just_set_result = true;
+ }
break;
+ }
/* These should never appear during verification. */
+ case Instruction::UNUSED_3E:
+ case Instruction::UNUSED_3F:
+ case Instruction::UNUSED_40:
+ case Instruction::UNUSED_41:
+ case Instruction::UNUSED_42:
+ case Instruction::UNUSED_43:
+ case Instruction::UNUSED_73:
+ case Instruction::UNUSED_79:
+ case Instruction::UNUSED_7A:
+ case Instruction::UNUSED_EB:
+ case Instruction::UNUSED_EC:
case Instruction::UNUSED_ED:
case Instruction::UNUSED_EE:
case Instruction::UNUSED_EF:
+ case Instruction::UNUSED_F0:
+ case Instruction::UNUSED_F1:
case Instruction::UNUSED_F2:
case Instruction::UNUSED_F3:
case Instruction::UNUSED_F4:
@@ -2250,30 +2485,9 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
case Instruction::UNUSED_F9:
case Instruction::UNUSED_FA:
case Instruction::UNUSED_FB:
- case Instruction::UNUSED_F0:
- case Instruction::UNUSED_F1:
- case Instruction::UNUSED_E3:
- case Instruction::UNUSED_E8:
- case Instruction::UNUSED_E7:
- case Instruction::UNUSED_E4:
- case Instruction::UNUSED_E9:
case Instruction::UNUSED_FC:
- case Instruction::UNUSED_E5:
- case Instruction::UNUSED_EA:
case Instruction::UNUSED_FD:
- case Instruction::UNUSED_E6:
- case Instruction::UNUSED_EB:
case Instruction::UNUSED_FE:
- case Instruction::UNUSED_3E:
- case Instruction::UNUSED_3F:
- case Instruction::UNUSED_40:
- case Instruction::UNUSED_41:
- case Instruction::UNUSED_42:
- case Instruction::UNUSED_43:
- case Instruction::UNUSED_73:
- case Instruction::UNUSED_79:
- case Instruction::UNUSED_7A:
- case Instruction::UNUSED_EC:
case Instruction::UNUSED_FF:
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Unexpected opcode " << inst->DumpString(dex_file_);
break;
@@ -2305,33 +2519,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
work_line_->SetResultTypeToUnknown();
}
- /* Handle "continue". Tag the next consecutive instruction. */
- if ((opcode_flags & Instruction::kContinue) != 0) {
- uint32_t next_insn_idx = work_insn_idx_ + CurrentInsnFlags()->GetLengthInCodeUnits();
- if (next_insn_idx >= code_item_->insns_size_in_code_units_) {
- Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Execution can walk off end of code area";
- return false;
- }
- // The only way to get to a move-exception instruction is to get thrown there. Make sure the
- // next instruction isn't one.
- if (!CheckNotMoveException(code_item_->insns_, next_insn_idx)) {
- return false;
- }
- RegisterLine* next_line = reg_table_.GetLine(next_insn_idx);
- if (next_line != NULL) {
- // Merge registers into what we have for the next instruction, and set the "changed" flag if
- // needed.
- if (!UpdateRegisters(next_insn_idx, work_line_.get())) {
- return false;
- }
- } else {
- /*
- * We're not recording register data for the next instruction, so we don't know what the prior
- * state was. We have to assume that something has changed and re-evaluate it.
- */
- insn_flags_[next_insn_idx].SetChanged();
- }
- }
+
/*
* Handle "branch". Tag the branch target.
@@ -2357,8 +2545,14 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
return false;
}
/* update branch target, set "changed" if appropriate */
- if (!UpdateRegisters(work_insn_idx_ + branch_target, work_line_.get())) {
- return false;
+ if (NULL != branch_line.get()) {
+ if (!UpdateRegisters(work_insn_idx_ + branch_target, branch_line.get())) {
+ return false;
+ }
+ } else {
+ if (!UpdateRegisters(work_insn_idx_ + branch_target, work_line_.get())) {
+ return false;
+ }
}
}
@@ -2433,7 +2627,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
* monitor-enter and the monitor stack was empty, we don't need a catch-all (if it throws,
* it will do so before grabbing the lock).
*/
- if (dec_insn.opcode != Instruction::MONITOR_ENTER || work_line_->MonitorStackDepth() != 1) {
+ if (inst->Opcode() != Instruction::MONITOR_ENTER || work_line_->MonitorStackDepth() != 1) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD)
<< "expected to be within a catch-all for an instruction where a monitor is held";
return false;
@@ -2441,6 +2635,42 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
}
}
+ /* Handle "continue". Tag the next consecutive instruction.
+ * Note: Keep the code handling "continue" case below the "branch" and "switch" cases,
+ * because it changes work_line_ when performing peephole optimization
+ * and this change should not be used in those cases.
+ */
+ if ((opcode_flags & Instruction::kContinue) != 0) {
+ uint32_t next_insn_idx = work_insn_idx_ + CurrentInsnFlags()->GetLengthInCodeUnits();
+ if (next_insn_idx >= code_item_->insns_size_in_code_units_) {
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Execution can walk off end of code area";
+ return false;
+ }
+ // The only way to get to a move-exception instruction is to get thrown there. Make sure the
+ // next instruction isn't one.
+ if (!CheckNotMoveException(code_item_->insns_, next_insn_idx)) {
+ return false;
+ }
+ if (NULL != fallthrough_line.get()) {
+ // Make workline consistent with fallthrough computed from peephole optimization.
+ work_line_->CopyFromLine(fallthrough_line.get());
+ }
+ RegisterLine* next_line = reg_table_.GetLine(next_insn_idx);
+ if (next_line != NULL) {
+ // Merge registers into what we have for the next instruction,
+ // and set the "changed" flag if needed.
+ if (!UpdateRegisters(next_insn_idx, work_line_.get())) {
+ return false;
+ }
+ } else {
+ /*
+ * We're not recording register data for the next instruction, so we don't know what the
+ * prior state was. We have to assume that something has changed and re-evaluate it.
+ */
+ insn_flags_[next_insn_idx].SetChanged();
+ }
+ }
+
/* If we're returning from the method, make sure monitor stack is empty. */
if ((opcode_flags & Instruction::kReturn) != 0) {
if (!work_line_->VerifyMonitorStackEmpty()) {
@@ -2472,7 +2702,8 @@ const RegType& MethodVerifier::ResolveClassAndCheckAccess(uint32_t class_idx) {
const RegType& referrer = GetDeclaringClass();
mirror::Class* klass = dex_cache_->GetResolvedType(class_idx);
const RegType& result =
- klass != NULL ? reg_types_.FromClass(klass, klass->IsFinal())
+ klass != NULL ? reg_types_.FromClass(descriptor, klass,
+ klass->CannotBeAssignedFromOtherTypes())
: reg_types_.FromDescriptor(class_loader_, descriptor, false);
if (result.IsConflict()) {
Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "accessing broken descriptor '" << descriptor
@@ -2625,12 +2856,14 @@ mirror::AbstractMethod* MethodVerifier::ResolveMethodAndCheckAccess(uint32_t dex
return res_method;
}
-mirror::AbstractMethod* MethodVerifier::VerifyInvocationArgs(const DecodedInstruction& dec_insn,
- MethodType method_type, bool is_range,
+mirror::AbstractMethod* MethodVerifier::VerifyInvocationArgs(const Instruction* inst,
+ MethodType method_type,
+ bool is_range,
bool is_super) {
// Resolve the method. This could be an abstract or concrete method depending on what sort of call
// we're making.
- mirror::AbstractMethod* res_method = ResolveMethodAndCheckAccess(dec_insn.vB, method_type);
+ const uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
+ mirror::AbstractMethod* res_method = ResolveMethodAndCheckAccess(method_idx, method_type);
if (res_method == NULL) { // error or class is unresolved
return NULL;
}
@@ -2658,9 +2891,9 @@ mirror::AbstractMethod* MethodVerifier::VerifyInvocationArgs(const DecodedInstru
}
}
// We use vAA as our expected arg count, rather than res_method->insSize, because we need to
- // match the call to the signature. Also, we might might be calling through an abstract method
+ // match the call to the signature. Also, we might be calling through an abstract method
// definition (which doesn't have register count values).
- size_t expected_args = dec_insn.vA;
+ const size_t expected_args = (is_range) ? inst->VRegA_3rc() : inst->VRegA_35c();
/* caught by static verifier */
DCHECK(is_range || expected_args <= 5);
if (expected_args > code_item_->outs_size_) {
@@ -2676,7 +2909,7 @@ mirror::AbstractMethod* MethodVerifier::VerifyInvocationArgs(const DecodedInstru
*/
size_t actual_args = 0;
if (!res_method->IsStatic()) {
- const RegType& actual_arg_type = work_line_->GetInvocationThis(dec_insn);
+ const RegType& actual_arg_type = work_line_->GetInvocationThis(inst, is_range);
if (actual_arg_type.IsConflict()) { // GetInvocationThis failed.
return NULL;
}
@@ -2686,7 +2919,9 @@ mirror::AbstractMethod* MethodVerifier::VerifyInvocationArgs(const DecodedInstru
}
if (method_type != METHOD_INTERFACE && !actual_arg_type.IsZero()) {
mirror::Class* klass = res_method->GetDeclaringClass();
- const RegType& res_method_class = reg_types_.FromClass(klass, klass->IsFinal());
+ const RegType& res_method_class =
+ reg_types_.FromClass(ClassHelper(klass).GetDescriptor(), klass,
+ klass->CannotBeAssignedFromOtherTypes());
if (!res_method_class.IsAssignableFrom(actual_arg_type)) {
Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "'this' argument '" << actual_arg_type
<< "' not instance of '" << res_method_class << "'";
@@ -2702,6 +2937,10 @@ mirror::AbstractMethod* MethodVerifier::VerifyInvocationArgs(const DecodedInstru
MethodHelper mh(res_method);
const DexFile::TypeList* params = mh.GetParameterTypeList();
size_t params_size = params == NULL ? 0 : params->Size();
+ uint32_t arg[5];
+ if (!is_range) {
+ inst->GetArgs(arg);
+ }
for (size_t param_index = 0; param_index < params_size; param_index++) {
if (actual_args >= expected_args) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Rejecting invalid call to '" << PrettyMethod(res_method)
@@ -2717,7 +2956,7 @@ mirror::AbstractMethod* MethodVerifier::VerifyInvocationArgs(const DecodedInstru
return NULL;
}
const RegType& reg_type = reg_types_.FromDescriptor(class_loader_, descriptor, false);
- uint32_t get_reg = is_range ? dec_insn.vC + actual_args : dec_insn.arg[actual_args];
+ uint32_t get_reg = is_range ? inst->VRegC_3rc() + actual_args : arg[actual_args];
if (!work_line_->VerifyRegisterType(get_reg, reg_type)) {
return res_method;
}
@@ -2732,9 +2971,142 @@ mirror::AbstractMethod* MethodVerifier::VerifyInvocationArgs(const DecodedInstru
}
}
-void MethodVerifier::VerifyNewArray(const DecodedInstruction& dec_insn, bool is_filled,
- bool is_range) {
- const RegType& res_type = ResolveClassAndCheckAccess(is_filled ? dec_insn.vB : dec_insn.vC);
+mirror::AbstractMethod* MethodVerifier::GetQuickInvokedMethod(const Instruction* inst,
+ RegisterLine* reg_line,
+ bool is_range) {
+ DCHECK(inst->Opcode() == Instruction::INVOKE_VIRTUAL_QUICK ||
+ inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE_QUICK);
+ const RegType& actual_arg_type = reg_line->GetInvocationThis(inst, is_range);
+ if (actual_arg_type.IsConflict()) { // GetInvocationThis failed.
+ return NULL;
+ }
+ mirror::Class* this_class = NULL;
+ if (!actual_arg_type.IsUnresolvedTypes()) {
+ this_class = actual_arg_type.GetClass();
+ } else {
+ const std::string& descriptor(actual_arg_type.GetDescriptor());
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ this_class = class_linker->FindClass(descriptor.c_str(), class_loader_);
+ if (this_class == NULL) {
+ Thread::Current()->ClearException();
+ // Look for a system class
+ this_class = class_linker->FindClass(descriptor.c_str(), NULL);
+ }
+ }
+ if (this_class == NULL) {
+ return NULL;
+ }
+ mirror::ObjectArray<mirror::AbstractMethod>* vtable = this_class->GetVTable();
+ CHECK(vtable != NULL);
+ uint16_t vtable_index = is_range ? inst->VRegB_3rc() : inst->VRegB_35c();
+ CHECK(vtable_index < vtable->GetLength());
+ mirror::AbstractMethod* res_method = vtable->Get(vtable_index);
+ CHECK(!Thread::Current()->IsExceptionPending());
+ return res_method;
+}
+
+mirror::AbstractMethod* MethodVerifier::VerifyInvokeVirtualQuickArgs(const Instruction* inst,
+ bool is_range) {
+ DCHECK(Runtime::Current()->IsStarted());
+ mirror::AbstractMethod* res_method = GetQuickInvokedMethod(inst, work_line_.get(),
+ is_range);
+ if (res_method == NULL) {
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Cannot infer method from " << inst->Name();
+ return NULL;
+ }
+ CHECK(!res_method->IsDirect() && !res_method->IsStatic());
+
+ // We use vAA as our expected arg count, rather than res_method->insSize, because we need to
+ // match the call to the signature. Also, we might be calling through an abstract method
+ // definition (which doesn't have register count values).
+ const RegType& actual_arg_type = work_line_->GetInvocationThis(inst, is_range);
+ if (actual_arg_type.IsConflict()) { // GetInvocationThis failed.
+ return NULL;
+ }
+ const size_t expected_args = (is_range) ? inst->VRegA_3rc() : inst->VRegA_35c();
+ /* caught by static verifier */
+ DCHECK(is_range || expected_args <= 5);
+ if (expected_args > code_item_->outs_size_) {
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid argument count (" << expected_args
+ << ") exceeds outsSize (" << code_item_->outs_size_ << ")";
+ return NULL;
+ }
+
+ /*
+ * Check the "this" argument, which must be an instance of the class that declared the method.
+ * For an interface class, we don't do the full interface merge (see JoinClass), so we can't do a
+ * rigorous check here (which is okay since we have to do it at runtime).
+ */
+ if (actual_arg_type.IsUninitializedReference() && !res_method->IsConstructor()) {
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "'this' arg must be initialized";
+ return NULL;
+ }
+ if (!actual_arg_type.IsZero()) {
+ mirror::Class* klass = res_method->GetDeclaringClass();
+ const RegType& res_method_class =
+ reg_types_.FromClass(ClassHelper(klass).GetDescriptor(), klass,
+ klass->CannotBeAssignedFromOtherTypes());
+ if (!res_method_class.IsAssignableFrom(actual_arg_type)) {
+ Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "'this' argument '" << actual_arg_type
+ << "' not instance of '" << res_method_class << "'";
+ return NULL;
+ }
+ }
+ /*
+ * Process the target method's signature. This signature may or may not
+ * have been verified, so we can't assume it's properly formed.
+ */
+ MethodHelper mh(res_method);
+ const DexFile::TypeList* params = mh.GetParameterTypeList();
+ size_t params_size = params == NULL ? 0 : params->Size();
+ uint32_t arg[5];
+ if (!is_range) {
+ inst->GetArgs(arg);
+ }
+ size_t actual_args = 1;
+ for (size_t param_index = 0; param_index < params_size; param_index++) {
+ if (actual_args >= expected_args) {
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Rejecting invalid call to '" << PrettyMethod(res_method)
+ << "'. Expected " << expected_args << " arguments, processing argument " << actual_args
+ << " (where longs/doubles count twice).";
+ return NULL;
+ }
+ const char* descriptor =
+ mh.GetTypeDescriptorFromTypeIdx(params->GetTypeItem(param_index).type_idx_);
+ if (descriptor == NULL) {
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Rejecting invocation of " << PrettyMethod(res_method)
+ << " missing signature component";
+ return NULL;
+ }
+ const RegType& reg_type = reg_types_.FromDescriptor(class_loader_, descriptor, false);
+ uint32_t get_reg = is_range ? inst->VRegC_3rc() + actual_args : arg[actual_args];
+ if (!work_line_->VerifyRegisterType(get_reg, reg_type)) {
+ return res_method;
+ }
+ actual_args = reg_type.IsLongOrDoubleTypes() ? actual_args + 2 : actual_args + 1;
+ }
+ if (actual_args != expected_args) {
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Rejecting invocation of " << PrettyMethod(res_method)
+ << " expected " << expected_args << " arguments, found " << actual_args;
+ return NULL;
+ } else {
+ return res_method;
+ }
+}
+
+void MethodVerifier::VerifyNewArray(const Instruction* inst, bool is_filled, bool is_range) {
+ uint32_t type_idx;
+ if (!is_filled) {
+ DCHECK_EQ(inst->Opcode(), Instruction::NEW_ARRAY);
+ type_idx = inst->VRegC_22c();
+ } else if (!is_range) {
+ DCHECK_EQ(inst->Opcode(), Instruction::FILLED_NEW_ARRAY);
+ type_idx = inst->VRegB_35c();
+ } else {
+ DCHECK_EQ(inst->Opcode(), Instruction::FILLED_NEW_ARRAY_RANGE);
+ type_idx = inst->VRegB_3rc();
+ }
+ const RegType& res_type = ResolveClassAndCheckAccess(type_idx);
if (res_type.IsConflict()) { // bad class
DCHECK_NE(failures_.size(), 0U);
} else {
@@ -2743,43 +3115,49 @@ void MethodVerifier::VerifyNewArray(const DecodedInstruction& dec_insn, bool is_
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "new-array on non-array class " << res_type;
} else if (!is_filled) {
/* make sure "size" register is valid type */
- work_line_->VerifyRegisterType(dec_insn.vB, reg_types_.Integer());
+ work_line_->VerifyRegisterType(inst->VRegB_22c(), reg_types_.Integer());
/* set register type to array class */
- work_line_->SetRegisterType(dec_insn.vA, res_type);
+ const RegType& precise_type = reg_types_.FromUninitialized(res_type);
+ work_line_->SetRegisterType(inst->VRegA_22c(), precise_type);
} else {
// Verify each register. If "arg_count" is bad, VerifyRegisterType() will run off the end of
// the list and fail. It's legal, if silly, for arg_count to be zero.
const RegType& expected_type = reg_types_.GetComponentType(res_type, class_loader_);
- uint32_t arg_count = dec_insn.vA;
+ uint32_t arg_count = (is_range) ? inst->VRegA_3rc() : inst->VRegA_35c();
+ uint32_t arg[5];
+ if (!is_range) {
+ inst->GetArgs(arg);
+ }
for (size_t ui = 0; ui < arg_count; ui++) {
- uint32_t get_reg = is_range ? dec_insn.vC + ui : dec_insn.arg[ui];
+ uint32_t get_reg = is_range ? inst->VRegC_3rc() + ui : arg[ui];
if (!work_line_->VerifyRegisterType(get_reg, expected_type)) {
work_line_->SetResultRegisterType(reg_types_.Conflict());
return;
}
}
// filled-array result goes into "result" register
- work_line_->SetResultRegisterType(res_type);
+ const RegType& precise_type = reg_types_.FromUninitialized(res_type);
+ work_line_->SetResultRegisterType(precise_type);
}
}
}
-void MethodVerifier::VerifyAGet(const DecodedInstruction& dec_insn,
+void MethodVerifier::VerifyAGet(const Instruction* inst,
const RegType& insn_type, bool is_primitive) {
- const RegType& index_type = work_line_->GetRegisterType(dec_insn.vC);
+ const RegType& index_type = work_line_->GetRegisterType(inst->VRegC_23x());
if (!index_type.IsArrayIndexTypes()) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Invalid reg type for array index (" << index_type << ")";
} else {
- const RegType& array_type = work_line_->GetRegisterType(dec_insn.vB);
+ const RegType& array_type = work_line_->GetRegisterType(inst->VRegB_23x());
if (array_type.IsZero()) {
// Null array class; this code path will fail at runtime. Infer a merge-able type from the
// instruction type. TODO: have a proper notion of bottom here.
if (!is_primitive || insn_type.IsCategory1Types()) {
// Reference or category 1
- work_line_->SetRegisterType(dec_insn.vA, reg_types_.Zero());
+ work_line_->SetRegisterType(inst->VRegA_23x(), reg_types_.Zero());
} else {
// Category 2
- work_line_->SetRegisterTypeWide(dec_insn.vA, reg_types_.FromCat2ConstLo(0, false),
+ work_line_->SetRegisterTypeWide(inst->VRegA_23x(), reg_types_.FromCat2ConstLo(0, false),
reg_types_.FromCat2ConstHi(0, false));
}
} else if (!array_type.IsArrayTypes()) {
@@ -2803,9 +3181,9 @@ void MethodVerifier::VerifyAGet(const DecodedInstruction& dec_insn,
// instruction, which can't differentiate object types and ints from floats, longs from
// doubles.
if (!component_type.IsLowHalf()) {
- work_line_->SetRegisterType(dec_insn.vA, component_type);
+ work_line_->SetRegisterType(inst->VRegA_23x(), component_type);
} else {
- work_line_->SetRegisterTypeWide(dec_insn.vA, component_type,
+ work_line_->SetRegisterTypeWide(inst->VRegA_23x(), component_type,
component_type.HighHalf(&reg_types_));
}
}
@@ -2813,13 +3191,13 @@ void MethodVerifier::VerifyAGet(const DecodedInstruction& dec_insn,
}
}
-void MethodVerifier::VerifyAPut(const DecodedInstruction& dec_insn,
+void MethodVerifier::VerifyAPut(const Instruction* inst,
const RegType& insn_type, bool is_primitive) {
- const RegType& index_type = work_line_->GetRegisterType(dec_insn.vC);
+ const RegType& index_type = work_line_->GetRegisterType(inst->VRegC_23x());
if (!index_type.IsArrayIndexTypes()) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Invalid reg type for array index (" << index_type << ")";
} else {
- const RegType& array_type = work_line_->GetRegisterType(dec_insn.vB);
+ const RegType& array_type = work_line_->GetRegisterType(inst->VRegB_23x());
if (array_type.IsZero()) {
// Null array type; this code path will fail at runtime. Infer a merge-able type from the
// instruction type.
@@ -2843,7 +3221,7 @@ void MethodVerifier::VerifyAPut(const DecodedInstruction& dec_insn,
// The instruction agrees with the type of array, confirm the value to be stored does too
// Note: we use the instruction type (rather than the component type) for aput-object as
// incompatible classes will be caught at runtime as an array store exception
- work_line_->VerifyRegisterType(dec_insn.vA, is_primitive ? component_type : insn_type);
+ work_line_->VerifyRegisterType(inst->VRegA_23x(), is_primitive ? component_type : insn_type);
}
}
}
@@ -2865,7 +3243,7 @@ mirror::Field* MethodVerifier::GetStaticField(int field_idx) {
mirror::Field* field = Runtime::Current()->GetClassLinker()->ResolveFieldJLS(*dex_file_, field_idx,
dex_cache_, class_loader_);
if (field == NULL) {
- LOG(INFO) << "unable to resolve static field " << field_idx << " ("
+ LOG(INFO) << "Unable to resolve static field " << field_idx << " ("
<< dex_file_->GetFieldName(field_id) << ") in "
<< dex_file_->GetFieldDeclaringClassDescriptor(field_id);
DCHECK(Thread::Current()->IsExceptionPending());
@@ -2900,7 +3278,7 @@ mirror::Field* MethodVerifier::GetInstanceField(const RegType& obj_type, int fie
mirror::Field* field = Runtime::Current()->GetClassLinker()->ResolveFieldJLS(*dex_file_, field_idx,
dex_cache_, class_loader_);
if (field == NULL) {
- LOG(INFO) << "unable to resolve instance field " << field_idx << " ("
+ LOG(INFO) << "Unable to resolve instance field " << field_idx << " ("
<< dex_file_->GetFieldName(field_id) << ") in "
<< dex_file_->GetFieldDeclaringClassDescriptor(field_id);
DCHECK(Thread::Current()->IsExceptionPending());
@@ -2920,7 +3298,9 @@ mirror::Field* MethodVerifier::GetInstanceField(const RegType& obj_type, int fie
return field;
} else {
mirror::Class* klass = field->GetDeclaringClass();
- const RegType& field_klass = reg_types_.FromClass(klass, klass->IsFinal());
+ const RegType& field_klass =
+ reg_types_.FromClass(dex_file_->GetFieldDeclaringClassDescriptor(field_id),
+ klass, klass->CannotBeAssignedFromOtherTypes());
if (obj_type.IsUninitializedTypes() &&
(!IsConstructor() || GetDeclaringClass().Equals(obj_type) ||
!field_klass.Equals(GetDeclaringClass()))) {
@@ -2943,14 +3323,14 @@ mirror::Field* MethodVerifier::GetInstanceField(const RegType& obj_type, int fie
}
}
-void MethodVerifier::VerifyISGet(const DecodedInstruction& dec_insn,
- const RegType& insn_type, bool is_primitive, bool is_static) {
- uint32_t field_idx = is_static ? dec_insn.vB : dec_insn.vC;
+void MethodVerifier::VerifyISGet(const Instruction* inst, const RegType& insn_type,
+ bool is_primitive, bool is_static) {
+ uint32_t field_idx = is_static ? inst->VRegB_21c() : inst->VRegC_22c();
mirror::Field* field;
if (is_static) {
field = GetStaticField(field_idx);
} else {
- const RegType& object_type = work_line_->GetRegisterType(dec_insn.vB);
+ const RegType& object_type = work_line_->GetRegisterType(inst->VRegB_22c());
field = GetInstanceField(object_type, field_idx);
}
const char* descriptor;
@@ -2964,6 +3344,7 @@ void MethodVerifier::VerifyISGet(const DecodedInstruction& dec_insn,
loader = class_loader_;
}
const RegType& field_type = reg_types_.FromDescriptor(loader, descriptor, false);
+ const uint32_t vregA = (is_static) ? inst->VRegA_21c() : inst->VRegA_22c();
if (is_primitive) {
if (field_type.Equals(insn_type) ||
(field_type.IsFloat() && insn_type.IsIntegralTypes()) ||
@@ -2985,25 +3366,25 @@ void MethodVerifier::VerifyISGet(const DecodedInstruction& dec_insn,
<< " to be compatible with type '" << insn_type
<< "' but found type '" << field_type
<< "' in get-object";
- work_line_->SetRegisterType(dec_insn.vA, reg_types_.Conflict());
+ work_line_->SetRegisterType(vregA, reg_types_.Conflict());
return;
}
}
if (!field_type.IsLowHalf()) {
- work_line_->SetRegisterType(dec_insn.vA, field_type);
+ work_line_->SetRegisterType(vregA, field_type);
} else {
- work_line_->SetRegisterTypeWide(dec_insn.vA, field_type, field_type.HighHalf(&reg_types_));
+ work_line_->SetRegisterTypeWide(vregA, field_type, field_type.HighHalf(&reg_types_));
}
}
-void MethodVerifier::VerifyISPut(const DecodedInstruction& dec_insn,
- const RegType& insn_type, bool is_primitive, bool is_static) {
- uint32_t field_idx = is_static ? dec_insn.vB : dec_insn.vC;
+void MethodVerifier::VerifyISPut(const Instruction* inst, const RegType& insn_type,
+ bool is_primitive, bool is_static) {
+ uint32_t field_idx = is_static ? inst->VRegB_21c() : inst->VRegC_22c();
mirror::Field* field;
if (is_static) {
field = GetStaticField(field_idx);
} else {
- const RegType& object_type = work_line_->GetRegisterType(dec_insn.vB);
+ const RegType& object_type = work_line_->GetRegisterType(inst->VRegB_22c());
field = GetInstanceField(object_type, field_idx);
}
const char* descriptor;
@@ -3024,11 +3405,12 @@ void MethodVerifier::VerifyISPut(const DecodedInstruction& dec_insn,
return;
}
}
+ const uint32_t vregA = (is_static) ? inst->VRegA_21c() : inst->VRegA_22c();
if (is_primitive) {
// Primitive field assignability rules are weaker than regular assignability rules
bool instruction_compatible;
bool value_compatible;
- const RegType& value_type = work_line_->GetRegisterType(dec_insn.vA);
+ const RegType& value_type = work_line_->GetRegisterType(vregA);
if (field_type.IsIntegralTypes()) {
instruction_compatible = insn_type.IsIntegralTypes();
value_compatible = value_type.IsIntegralTypes();
@@ -3056,7 +3438,7 @@ void MethodVerifier::VerifyISPut(const DecodedInstruction& dec_insn,
return;
}
if (!value_compatible) {
- Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "unexpected value in v" << dec_insn.vA
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "unexpected value in v" << vregA
<< " of type " << value_type
<< " but expected " << field_type
<< " for store to " << PrettyField(field) << " in put";
@@ -3070,7 +3452,176 @@ void MethodVerifier::VerifyISPut(const DecodedInstruction& dec_insn,
<< "' in put-object";
return;
}
- work_line_->VerifyRegisterType(dec_insn.vA, field_type);
+ work_line_->VerifyRegisterType(vregA, field_type);
+ }
+}
+
+// Look for an instance field with this offset.
+// TODO: we may speed up the search if offsets are sorted by doing a quick search.
+static mirror::Field* FindInstanceFieldWithOffset(const mirror::Class* klass,
+ uint32_t field_offset)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ const mirror::ObjectArray<mirror::Field>* instance_fields = klass->GetIFields();
+ if (instance_fields != NULL) {
+ for (int32_t i = 0, e = instance_fields->GetLength(); i < e; ++i) {
+ mirror::Field* field = instance_fields->Get(i);
+ if (field->GetOffset().Uint32Value() == field_offset) {
+ return field;
+ }
+ }
+ }
+ // We did not find field in class: look into superclass.
+ if (klass->GetSuperClass() != NULL) {
+ return FindInstanceFieldWithOffset(klass->GetSuperClass(), field_offset);
+ } else {
+ return NULL;
+ }
+}
+
+// Returns the access field of a quick field access (iget/iput-quick) or NULL
+// if it cannot be found.
+mirror::Field* MethodVerifier::GetQuickFieldAccess(const Instruction* inst,
+ RegisterLine* reg_line) {
+ DCHECK(inst->Opcode() == Instruction::IGET_QUICK ||
+ inst->Opcode() == Instruction::IGET_WIDE_QUICK ||
+ inst->Opcode() == Instruction::IGET_OBJECT_QUICK ||
+ inst->Opcode() == Instruction::IPUT_QUICK ||
+ inst->Opcode() == Instruction::IPUT_WIDE_QUICK ||
+ inst->Opcode() == Instruction::IPUT_OBJECT_QUICK);
+ const RegType& object_type = reg_line->GetRegisterType(inst->VRegB_22c());
+ mirror::Class* object_class = NULL;
+ if (!object_type.IsUnresolvedTypes()) {
+ object_class = object_type.GetClass();
+ } else {
+ // We need to resolve the class from its descriptor.
+ const std::string& descriptor(object_type.GetDescriptor());
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ object_class = class_linker->FindClass(descriptor.c_str(), class_loader_);
+ if (object_class == NULL) {
+ Thread::Current()->ClearException();
+ // Look for a system class
+ object_class = class_linker->FindClass(descriptor.c_str(), NULL);
+ }
+ }
+ if (object_class == NULL) {
+ // Failed to get the Class* from reg type.
+ LOG(WARNING) << "Failed to get Class* from " << object_type;
+ return NULL;
+ }
+ uint32_t field_offset = static_cast<uint32_t>(inst->VRegC_22c());
+ return FindInstanceFieldWithOffset(object_class, field_offset);
+}
+
+void MethodVerifier::VerifyIGetQuick(const Instruction* inst, const RegType& insn_type,
+ bool is_primitive) {
+ DCHECK(Runtime::Current()->IsStarted());
+ mirror::Field* field = GetQuickFieldAccess(inst, work_line_.get());
+ if (field == NULL) {
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Cannot infer field from " << inst->Name();
+ return;
+ }
+ const char* descriptor = FieldHelper(field).GetTypeDescriptor();
+ mirror::ClassLoader* loader = field->GetDeclaringClass()->GetClassLoader();
+ const RegType& field_type = reg_types_.FromDescriptor(loader, descriptor, false);
+ const uint32_t vregA = inst->VRegA_22c();
+ if (is_primitive) {
+ if (field_type.Equals(insn_type) ||
+ (field_type.IsFloat() && insn_type.IsIntegralTypes()) ||
+ (field_type.IsDouble() && insn_type.IsLongTypes())) {
+ // expected that read is of the correct primitive type or that int reads are reading
+ // floats or long reads are reading doubles
+ } else {
+ // This is a global failure rather than a class change failure as the instructions and
+ // the descriptors for the type should have been consistent within the same file at
+ // compile time
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "expected field " << PrettyField(field)
+ << " to be of type '" << insn_type
+ << "' but found type '" << field_type << "' in get";
+ return;
+ }
+ } else {
+ if (!insn_type.IsAssignableFrom(field_type)) {
+ Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "expected field " << PrettyField(field)
+ << " to be compatible with type '" << insn_type
+ << "' but found type '" << field_type
+ << "' in get-object";
+ work_line_->SetRegisterType(vregA, reg_types_.Conflict());
+ return;
+ }
+ }
+ if (!field_type.IsLowHalf()) {
+ work_line_->SetRegisterType(vregA, field_type);
+ } else {
+ work_line_->SetRegisterTypeWide(vregA, field_type, field_type.HighHalf(&reg_types_));
+ }
+}
+
+void MethodVerifier::VerifyIPutQuick(const Instruction* inst, const RegType& insn_type,
+ bool is_primitive) {
+ DCHECK(Runtime::Current()->IsStarted());
+ mirror::Field* field = GetQuickFieldAccess(inst, work_line_.get());
+ if (field == NULL) {
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Cannot infer field from " << inst->Name();
+ return;
+ }
+ const char* descriptor = FieldHelper(field).GetTypeDescriptor();
+ mirror::ClassLoader* loader = field->GetDeclaringClass()->GetClassLoader();
+ const RegType& field_type = reg_types_.FromDescriptor(loader, descriptor, false);
+ if (field != NULL) {
+ if (field->IsFinal() && field->GetDeclaringClass() != GetDeclaringClass().GetClass()) {
+ Fail(VERIFY_ERROR_ACCESS_FIELD) << "cannot modify final field " << PrettyField(field)
+ << " from other class " << GetDeclaringClass();
+ return;
+ }
+ }
+ const uint32_t vregA = inst->VRegA_22c();
+ if (is_primitive) {
+ // Primitive field assignability rules are weaker than regular assignability rules
+ bool instruction_compatible;
+ bool value_compatible;
+ const RegType& value_type = work_line_->GetRegisterType(vregA);
+ if (field_type.IsIntegralTypes()) {
+ instruction_compatible = insn_type.IsIntegralTypes();
+ value_compatible = value_type.IsIntegralTypes();
+ } else if (field_type.IsFloat()) {
+ instruction_compatible = insn_type.IsInteger(); // no [is]put-float, so expect [is]put-int
+ value_compatible = value_type.IsFloatTypes();
+ } else if (field_type.IsLong()) {
+ instruction_compatible = insn_type.IsLong();
+ value_compatible = value_type.IsLongTypes();
+ } else if (field_type.IsDouble()) {
+ instruction_compatible = insn_type.IsLong(); // no [is]put-double, so expect [is]put-long
+ value_compatible = value_type.IsDoubleTypes();
+ } else {
+ instruction_compatible = false; // reference field with primitive store
+ value_compatible = false; // unused
+ }
+ if (!instruction_compatible) {
+ // This is a global failure rather than a class change failure as the instructions and
+ // the descriptors for the type should have been consistent within the same file at
+ // compile time
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "expected field " << PrettyField(field)
+ << " to be of type '" << insn_type
+ << "' but found type '" << field_type
+ << "' in put";
+ return;
+ }
+ if (!value_compatible) {
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "unexpected value in v" << vregA
+ << " of type " << value_type
+ << " but expected " << field_type
+ << " for store to " << PrettyField(field) << " in put";
+ return;
+ }
+ } else {
+ if (!insn_type.IsAssignableFrom(field_type)) {
+ Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "expected field " << PrettyField(field)
+ << " to be compatible with type '" << insn_type
+ << "' but found type '" << field_type
+ << "' in put-object";
+ return;
+ }
+ work_line_->VerifyRegisterType(vregA, field_type);
}
}
@@ -3128,14 +3679,18 @@ const RegType& MethodVerifier::GetMethodReturnType() {
}
const RegType& MethodVerifier::GetDeclaringClass() {
- if (foo_method_ != NULL) {
- mirror::Class* klass = foo_method_->GetDeclaringClass();
- return reg_types_.FromClass(klass, klass->IsFinal());
- } else {
+ if (declaring_class_ == NULL) {
const DexFile::MethodId& method_id = dex_file_->GetMethodId(dex_method_idx_);
const char* descriptor = dex_file_->GetTypeDescriptor(dex_file_->GetTypeId(method_id.class_idx_));
- return reg_types_.FromDescriptor(class_loader_, descriptor, false);
+ if (mirror_method_ != NULL) {
+ mirror::Class* klass = mirror_method_->GetDeclaringClass();
+ declaring_class_ = &reg_types_.FromClass(descriptor, klass,
+ klass->CannotBeAssignedFromOtherTypes());
+ } else {
+ declaring_class_ = &reg_types_.FromDescriptor(class_loader_, descriptor, false);
+ }
}
+ return *declaring_class_;
}
void MethodVerifier::ComputeGcMapSizes(size_t* gc_points, size_t* ref_bitmap_bits,
@@ -3160,7 +3715,39 @@ void MethodVerifier::ComputeGcMapSizes(size_t* gc_points, size_t* ref_bitmap_bit
*log2_max_gc_pc = i;
}
-MethodVerifier::PcToConreteMethod* MethodVerifier::GenerateDevirtMap() {
+MethodVerifier::MethodSafeCastSet* MethodVerifier::GenerateSafeCastSet() {
+ /*
+ * Walks over the method code and adds any cast instructions in which
+ * the type cast is implicit to a set, which is used in the code generation
+ * to elide these casts.
+ */
+ if (!failure_messages_.empty()) {
+ return NULL;
+ }
+ UniquePtr<MethodSafeCastSet> mscs;
+ const Instruction* inst = Instruction::At(code_item_->insns_);
+ const Instruction* end = Instruction::At(code_item_->insns_ +
+ code_item_->insns_size_in_code_units_);
+
+ for (; inst < end; inst = inst->Next()) {
+ if (Instruction::CHECK_CAST != inst->Opcode()) {
+ continue;
+ }
+ uint32_t dex_pc = inst->GetDexPc(code_item_->insns_);
+ RegisterLine* line = reg_table_.GetLine(dex_pc);
+ const RegType& reg_type(line->GetRegisterType(inst->VRegA_21c()));
+ const RegType& cast_type = ResolveClassAndCheckAccess(inst->VRegB_21c());
+ if (cast_type.IsStrictlyAssignableFrom(reg_type)) {
+ if (mscs.get() == NULL) {
+ mscs.reset(new MethodSafeCastSet());
+ }
+ mscs->insert(dex_pc);
+ }
+ }
+ return mscs.release();
+}
+
+MethodVerifier::PcToConcreteMethodMap* MethodVerifier::GenerateDevirtMap() {
// It is risky to rely on reg_types for sharpening in cases of soft
// verification, we might end up sharpening to a wrong implementation. Just abort.
@@ -3168,39 +3755,43 @@ MethodVerifier::PcToConreteMethod* MethodVerifier::GenerateDevirtMap() {
return NULL;
}
- PcToConreteMethod* pc_to_concrete_method = new PcToConreteMethod();
- uint32_t dex_pc = 0;
+ UniquePtr<PcToConcreteMethodMap> pc_to_concrete_method_map;
const uint16_t* insns = code_item_->insns_ ;
const Instruction* inst = Instruction::At(insns);
+ const Instruction* end = Instruction::At(insns + code_item_->insns_size_in_code_units_);
- for (; dex_pc < code_item_->insns_size_in_code_units_;
- dex_pc += insn_flags_[dex_pc].GetLengthInCodeUnits(), inst = inst->Next()) {
-
+ for (; inst < end; inst = inst->Next()) {
bool is_virtual = (inst->Opcode() == Instruction::INVOKE_VIRTUAL) ||
(inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE);
bool is_interface = (inst->Opcode() == Instruction::INVOKE_INTERFACE) ||
(inst->Opcode() == Instruction::INVOKE_INTERFACE_RANGE);
- if(!(is_interface || is_virtual))
- continue;
-
- // Check if vC ("this" pointer in the instruction) has a precise type.
+ if(!is_interface && !is_virtual) {
+ continue;
+ }
+ // Get reg type for register holding the reference to the object that will be dispatched upon.
+ uint32_t dex_pc = inst->GetDexPc(insns);
RegisterLine* line = reg_table_.GetLine(dex_pc);
- DecodedInstruction dec_insn(inst);
- const RegType& reg_type(line->GetRegisterType(dec_insn.vC));
+ bool is_range = (inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE) ||
+ (inst->Opcode() == Instruction::INVOKE_INTERFACE_RANGE);
+ const RegType&
+ reg_type(line->GetRegisterType(is_range ? inst->VRegC_3rc() : inst->VRegC_35c()));
- if (!reg_type.IsPreciseReference()) {
- continue;
+ if (!reg_type.HasClass()) {
+ // We will compute devirtualization information only when we know the Class of the reg type.
+ continue;
}
-
- CHECK(!(reg_type.GetClass()->IsInterface()));
- // If the class is an array class, it can be both Abstract and final and so
- // the reg_type will be created as precise.
- CHECK(!(reg_type.GetClass()->IsAbstract()) || reg_type.GetClass()->IsArrayClass());
- // Find the abstract method.
- // vB has the method index.
- mirror::AbstractMethod* abstract_method = NULL ;
- abstract_method = dex_cache_->GetResolvedMethod(dec_insn.vB);
+ mirror::Class* reg_class = reg_type.GetClass();
+ if (reg_class->IsInterface()) {
+ // We can't devirtualize when the known type of the register is an interface.
+ continue;
+ }
+ if (reg_class->IsAbstract() && !reg_class->IsArrayClass()) {
+ // We can't devirtualize abstract classes except on arrays of abstract classes.
+ continue;
+ }
+ mirror::AbstractMethod* abstract_method =
+ dex_cache_->GetResolvedMethod(is_range ? inst->VRegB_3rc() : inst->VRegB_35c());
if(abstract_method == NULL) {
// If the method is not found in the cache this means that it was never found
// by ResolveMethodAndCheckAccess() called when verifying invoke_*.
@@ -3214,28 +3805,24 @@ MethodVerifier::PcToConreteMethod* MethodVerifier::GenerateDevirtMap() {
if (is_virtual) {
concrete_method = reg_type.GetClass()->FindVirtualMethodForVirtual(abstract_method);
}
-
- if(concrete_method == NULL) {
- // In cases where concrete_method is not found continue to the next invoke instead
- // of crashing.
+ if (concrete_method == NULL || concrete_method->IsAbstract()) {
+ // In cases where concrete_method is not found, or is abstract, continue to the next invoke.
continue;
}
-
- CHECK(!concrete_method->IsAbstract()) << PrettyMethod(concrete_method);
- // Build method reference.
- CompilerDriver::MethodReference concrete_ref(
- concrete_method->GetDeclaringClass()->GetDexCache()->GetDexFile(),
- concrete_method->GetDexMethodIndex());
- // Now Save the current PC and the concrete method reference to be used
- // in compiler driver.
- pc_to_concrete_method->Put(dex_pc, concrete_ref );
+ if (reg_type.IsPreciseReference() || concrete_method->IsFinal() ||
+ concrete_method->GetDeclaringClass()->IsFinal()) {
+ // If we knew exactly the class being dispatched upon, or if the target method cannot be
+ // overridden record the target to be used in the compiler driver.
+ if (pc_to_concrete_method_map.get() == NULL) {
+ pc_to_concrete_method_map.reset(new PcToConcreteMethodMap());
+ }
+ CompilerDriver::MethodReference concrete_ref(
+ concrete_method->GetDeclaringClass()->GetDexCache()->GetDexFile(),
+ concrete_method->GetDexMethodIndex());
+ pc_to_concrete_method_map->Put(dex_pc, concrete_ref);
}
-
- if (pc_to_concrete_method->size() == 0) {
- delete pc_to_concrete_method;
- return NULL ;
}
- return pc_to_concrete_method;
+ return pc_to_concrete_method_map.release();
}
const std::vector<uint8_t>* MethodVerifier::GenerateGcMap() {
@@ -3276,6 +3863,7 @@ const std::vector<uint8_t>* MethodVerifier::GenerateGcMap() {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Failed to encode GC map (size=" << table_size << ")";
return NULL;
}
+ table->reserve(table_size);
// Write table header
table->push_back(format | ((ref_bitmap_bytes >> DexPcToReferenceMap::kRegMapFormatShift) &
~DexPcToReferenceMap::kRegMapFormatMask));
@@ -3326,9 +3914,10 @@ void MethodVerifier::VerifyGcMap(const std::vector<uint8_t>& data) {
}
}
-void MethodVerifier::SetDexGcMap(CompilerDriver::MethodReference ref, const std::vector<uint8_t>& gc_map) {
+void MethodVerifier::SetDexGcMap(CompilerDriver::MethodReference ref,
+ const std::vector<uint8_t>& gc_map) {
{
- MutexLock mu(Thread::Current(), *dex_gc_maps_lock_);
+ WriterMutexLock mu(Thread::Current(), *dex_gc_maps_lock_);
DexGcMapTable::iterator it = dex_gc_maps_->find(ref);
if (it != dex_gc_maps_->end()) {
delete it->second;
@@ -3336,42 +3925,69 @@ void MethodVerifier::SetDexGcMap(CompilerDriver::MethodReference ref, const std:
}
dex_gc_maps_->Put(ref, &gc_map);
}
- CHECK(GetDexGcMap(ref) != NULL);
+ DCHECK(GetDexGcMap(ref) != NULL);
}
-void MethodVerifier::SetDevirtMap(CompilerDriver::MethodReference ref, const PcToConreteMethod* devirt_map) {
- MutexLock mu(Thread::Current(), *devirt_maps_lock_);
- DevirtualizationMapTable::iterator it = devirt_maps_->find(ref);
- if (it != devirt_maps_->end()) {
+void MethodVerifier::SetSafeCastMap(CompilerDriver::MethodReference ref,
+ const MethodSafeCastSet* cast_set) {
+ MutexLock mu(Thread::Current(), *safecast_map_lock_);
+ SafeCastMap::iterator it = safecast_map_->find(ref);
+ if (it != safecast_map_->end()) {
delete it->second;
- devirt_maps_->erase(it);
+ safecast_map_->erase(it);
}
- devirt_maps_->Put(ref, devirt_map);
- CHECK(devirt_maps_->find(ref) != devirt_maps_->end());
+ safecast_map_->Put(ref, cast_set);
+ CHECK(safecast_map_->find(ref) != safecast_map_->end());
+}
+
+bool MethodVerifier::IsSafeCast(CompilerDriver::MethodReference ref, uint32_t pc) {
+ MutexLock mu(Thread::Current(), *safecast_map_lock_);
+ SafeCastMap::const_iterator it = safecast_map_->find(ref);
+ if (it == safecast_map_->end()) {
+ return false;
+ }
+
+ // Look up the cast address in the set of safe casts
+ MethodVerifier::MethodSafeCastSet::const_iterator cast_it = it->second->find(pc);
+ return cast_it != it->second->end();
}
const std::vector<uint8_t>* MethodVerifier::GetDexGcMap(CompilerDriver::MethodReference ref) {
- MutexLock mu(Thread::Current(), *dex_gc_maps_lock_);
+ ReaderMutexLock mu(Thread::Current(), *dex_gc_maps_lock_);
DexGcMapTable::const_iterator it = dex_gc_maps_->find(ref);
if (it == dex_gc_maps_->end()) {
- LOG(WARNING) << "Didn't find GC map for: " << PrettyMethod(ref.second, *ref.first);
+ LOG(WARNING) << "Didn't find GC map for: " << PrettyMethod(ref.dex_method_index, *ref.dex_file);
return NULL;
}
CHECK(it->second != NULL);
return it->second;
}
-const CompilerDriver::MethodReference* MethodVerifier::GetDevirtMap(CompilerDriver::MethodReference ref, uint32_t pc) {
- MutexLock mu(Thread::Current(), *devirt_maps_lock_);
+void MethodVerifier::SetDevirtMap(CompilerDriver::MethodReference ref,
+ const PcToConcreteMethodMap* devirt_map) {
+ WriterMutexLock mu(Thread::Current(), *devirt_maps_lock_);
+ DevirtualizationMapTable::iterator it = devirt_maps_->find(ref);
+ if (it != devirt_maps_->end()) {
+ delete it->second;
+ devirt_maps_->erase(it);
+ }
+
+ devirt_maps_->Put(ref, devirt_map);
+ CHECK(devirt_maps_->find(ref) != devirt_maps_->end());
+}
+
+const CompilerDriver::MethodReference* MethodVerifier::GetDevirtMap(const CompilerDriver::MethodReference& ref,
+ uint32_t dex_pc) {
+ ReaderMutexLock mu(Thread::Current(), *devirt_maps_lock_);
DevirtualizationMapTable::const_iterator it = devirt_maps_->find(ref);
if (it == devirt_maps_->end()) {
return NULL;
}
// Look up the PC in the map, get the concrete method to execute and return its reference.
- MethodVerifier::PcToConreteMethod::const_iterator pc_to_concrete_method = it->second->find(pc);
+ MethodVerifier::PcToConcreteMethodMap::const_iterator pc_to_concrete_method = it->second->find(dex_pc);
if(pc_to_concrete_method != it->second->end()) {
return &(pc_to_concrete_method->second);
} else {
@@ -3423,26 +4039,36 @@ std::vector<int32_t> MethodVerifier::DescribeVRegs(uint32_t dex_pc) {
return result;
}
-Mutex* MethodVerifier::dex_gc_maps_lock_ = NULL;
+ReaderWriterMutex* MethodVerifier::dex_gc_maps_lock_ = NULL;
MethodVerifier::DexGcMapTable* MethodVerifier::dex_gc_maps_ = NULL;
-Mutex* MethodVerifier::devirt_maps_lock_ = NULL;
+Mutex* MethodVerifier::safecast_map_lock_ = NULL;
+MethodVerifier::SafeCastMap* MethodVerifier::safecast_map_ = NULL;
+
+ReaderWriterMutex* MethodVerifier::devirt_maps_lock_ = NULL;
MethodVerifier::DevirtualizationMapTable* MethodVerifier::devirt_maps_ = NULL;
Mutex* MethodVerifier::rejected_classes_lock_ = NULL;
MethodVerifier::RejectedClassesTable* MethodVerifier::rejected_classes_ = NULL;
void MethodVerifier::Init() {
- dex_gc_maps_lock_ = new Mutex("verifier GC maps lock");
+ dex_gc_maps_lock_ = new ReaderWriterMutex("verifier GC maps lock");
Thread* self = Thread::Current();
{
- MutexLock mu(self, *dex_gc_maps_lock_);
+ WriterMutexLock mu(self, *dex_gc_maps_lock_);
dex_gc_maps_ = new MethodVerifier::DexGcMapTable;
}
- devirt_maps_lock_ = new Mutex("verifier Devirtualization lock");
+ safecast_map_lock_ = new Mutex("verifier Cast Elision lock");
+ {
+ MutexLock mu(self, *safecast_map_lock_);
+ safecast_map_ = new MethodVerifier::SafeCastMap();
+ }
+
+ devirt_maps_lock_ = new ReaderWriterMutex("verifier Devirtualization lock");
+
{
- MutexLock mu(self, *devirt_maps_lock_);
+ WriterMutexLock mu(self, *devirt_maps_lock_);
devirt_maps_ = new MethodVerifier::DevirtualizationMapTable();
}
@@ -3457,7 +4083,7 @@ void MethodVerifier::Init() {
void MethodVerifier::Shutdown() {
Thread* self = Thread::Current();
{
- MutexLock mu(self, *dex_gc_maps_lock_);
+ WriterMutexLock mu(self, *dex_gc_maps_lock_);
STLDeleteValues(dex_gc_maps_);
delete dex_gc_maps_;
dex_gc_maps_ = NULL;
@@ -3466,7 +4092,7 @@ void MethodVerifier::Shutdown() {
dex_gc_maps_lock_ = NULL;
{
- MutexLock mu(self, *devirt_maps_lock_);
+ WriterMutexLock mu(self, *devirt_maps_lock_);
STLDeleteValues(devirt_maps_);
delete devirt_maps_;
devirt_maps_ = NULL;
diff --git a/src/verifier/method_verifier.h b/src/verifier/method_verifier.h
index ab7e3cc8dc..e90f9d95b0 100644
--- a/src/verifier/method_verifier.h
+++ b/src/verifier/method_verifier.h
@@ -187,15 +187,33 @@ class MethodVerifier {
static const std::vector<uint8_t>* GetDexGcMap(CompilerDriver::MethodReference ref)
LOCKS_EXCLUDED(dex_gc_maps_lock_);
- static const CompilerDriver::MethodReference* GetDevirtMap(CompilerDriver::MethodReference ref, uint32_t pc)
+ static const CompilerDriver::MethodReference* GetDevirtMap(const CompilerDriver::MethodReference& ref,
+ uint32_t dex_pc)
LOCKS_EXCLUDED(devirt_maps_lock_);
+ // Returns true if the cast can statically be verified to be redundant
+ // by using the check-cast elision peephole optimization in the verifier
+ static bool IsSafeCast(CompilerDriver::MethodReference ref, uint32_t pc)
+ LOCKS_EXCLUDED(safecast_map_lock_);
+
// Fills 'monitor_enter_dex_pcs' with the dex pcs of the monitor-enter instructions corresponding
- // to the locks held at 'dex_pc' in 'm'.
+ // to the locks held at 'dex_pc' in method 'm'.
static void FindLocksAtDexPc(mirror::AbstractMethod* m, uint32_t dex_pc,
std::vector<uint32_t>& monitor_enter_dex_pcs)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ // Returns the accessed field corresponding to the quick instruction's field
+ // offset at 'dex_pc' in method 'm'.
+ static mirror::Field* FindAccessedFieldAtDexPc(mirror::AbstractMethod* m,
+ uint32_t dex_pc)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ // Returns the invoked method corresponding to the quick instruction's vtable
+ // index at 'dex_pc' in method 'm'.
+ static mirror::AbstractMethod* FindInvokedMethodAtDexPc(mirror::AbstractMethod* m,
+ uint32_t dex_pc)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
static void Init() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
static void Shutdown();
@@ -248,6 +266,12 @@ class MethodVerifier {
void FindLocksAtDexPc() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ mirror::Field* FindAccessedFieldAtDexPc(uint32_t dex_pc)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ mirror::AbstractMethod* FindInvokedMethodAtDexPc(uint32_t dex_pc)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
/*
* Compute the width of the instruction at each address in the instruction stream, and store it in
* insn_flags_. Addresses that are in the middle of an instruction, or that are part of switch
@@ -447,19 +471,18 @@ class MethodVerifier {
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Perform verification of a new array instruction
- void VerifyNewArray(const DecodedInstruction& dec_insn, bool is_filled,
- bool is_range)
+ void VerifyNewArray(const Instruction* inst, bool is_filled, bool is_range)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Perform verification of an aget instruction. The destination register's type will be set to
// be that of component type of the array unless the array type is unknown, in which case a
// bottom type inferred from the type of instruction is used. is_primitive is false for an
// aget-object.
- void VerifyAGet(const DecodedInstruction& insn, const RegType& insn_type,
+ void VerifyAGet(const Instruction* inst, const RegType& insn_type,
bool is_primitive) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Perform verification of an aput instruction.
- void VerifyAPut(const DecodedInstruction& insn, const RegType& insn_type,
+ void VerifyAPut(const Instruction* inst, const RegType& insn_type,
bool is_primitive) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Lookup instance field and fail for resolution violations
@@ -470,15 +493,30 @@ class MethodVerifier {
mirror::Field* GetStaticField(int field_idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Perform verification of an iget or sget instruction.
- void VerifyISGet(const DecodedInstruction& insn, const RegType& insn_type,
+ void VerifyISGet(const Instruction* inst, const RegType& insn_type,
bool is_primitive, bool is_static)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Perform verification of an iput or sput instruction.
- void VerifyISPut(const DecodedInstruction& insn, const RegType& insn_type,
+ void VerifyISPut(const Instruction* inst, const RegType& insn_type,
bool is_primitive, bool is_static)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ // Returns the access field of a quick field access (iget/iput-quick) or NULL
+ // if it cannot be found.
+ mirror::Field* GetQuickFieldAccess(const Instruction* inst, RegisterLine* reg_line)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ // Perform verification of an iget-quick instruction.
+ void VerifyIGetQuick(const Instruction* inst, const RegType& insn_type,
+ bool is_primitive)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ // Perform verification of an iput-quick instruction.
+ void VerifyIPutQuick(const Instruction* inst, const RegType& insn_type,
+ bool is_primitive)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
// Resolves a class based on an index and performs access checks to ensure the referrer can
// access the resolved class.
const RegType& ResolveClassAndCheckAccess(uint32_t class_idx)
@@ -522,10 +560,20 @@ class MethodVerifier {
* Returns the resolved method on success, NULL on failure (with *failure
* set appropriately).
*/
- mirror::AbstractMethod* VerifyInvocationArgs(const DecodedInstruction& dec_insn,
- MethodType method_type, bool is_range, bool is_super)
+ mirror::AbstractMethod* VerifyInvocationArgs(const Instruction* inst,
+ MethodType method_type,
+ bool is_range, bool is_super)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ mirror::AbstractMethod* GetQuickInvokedMethod(const Instruction* inst,
+ RegisterLine* reg_line,
+ bool is_range)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ mirror::AbstractMethod* VerifyInvokeVirtualQuickArgs(const Instruction* inst,
+ bool is_range)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
/*
* Verify that the target instruction is not "move-exception". It's important that the only way
* to execute a move-exception is as the first instruction of an exception handler.
@@ -574,23 +622,36 @@ class MethodVerifier {
InstructionFlags* CurrentInsnFlags();
// All the GC maps that the verifier has created
- typedef SafeMap<const CompilerDriver::MethodReference, const std::vector<uint8_t>*> DexGcMapTable;
- static Mutex* dex_gc_maps_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
+ typedef SafeMap<const CompilerDriver::MethodReference, const std::vector<uint8_t>*,
+ CompilerDriver::MethodReferenceComparator> DexGcMapTable;
+ static ReaderWriterMutex* dex_gc_maps_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
static DexGcMapTable* dex_gc_maps_ GUARDED_BY(dex_gc_maps_lock_);
static void SetDexGcMap(CompilerDriver::MethodReference ref, const std::vector<uint8_t>& dex_gc_map)
LOCKS_EXCLUDED(dex_gc_maps_lock_);
+ // Cast elision types.
+ typedef std::set<uint32_t> MethodSafeCastSet;
+ typedef SafeMap<const CompilerDriver::MethodReference, const MethodSafeCastSet*,
+ CompilerDriver::MethodReferenceComparator> SafeCastMap;
+ MethodVerifier::MethodSafeCastSet* GenerateSafeCastSet()
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ static void SetSafeCastMap(CompilerDriver::MethodReference ref, const MethodSafeCastSet* mscs);
+ LOCKS_EXCLUDED(safecast_map_lock_);
+ static Mutex* safecast_map_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
+ static SafeCastMap* safecast_map_ GUARDED_BY(safecast_map_lock_);
+
// Devirtualization map.
- typedef SafeMap<const uint32_t, CompilerDriver::MethodReference> PcToConreteMethod;
- typedef SafeMap<const CompilerDriver::MethodReference, const PcToConreteMethod*>
- DevirtualizationMapTable;
- MethodVerifier::PcToConreteMethod* GenerateDevirtMap()
+ typedef SafeMap<const uint32_t, CompilerDriver::MethodReference> PcToConcreteMethodMap;
+ typedef SafeMap<const CompilerDriver::MethodReference, const PcToConcreteMethodMap*,
+ CompilerDriver::MethodReferenceComparator> DevirtualizationMapTable;
+ MethodVerifier::PcToConcreteMethodMap* GenerateDevirtMap()
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- static Mutex* devirt_maps_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
+ static ReaderWriterMutex* devirt_maps_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
static DevirtualizationMapTable* devirt_maps_ GUARDED_BY(devirt_maps_lock_);
- static void SetDevirtMap(CompilerDriver::MethodReference ref, const PcToConreteMethod* pc_method_map);
+ static void SetDevirtMap(CompilerDriver::MethodReference ref,
+ const PcToConcreteMethodMap* pc_method_map)
LOCKS_EXCLUDED(devirt_maps_lock_);
typedef std::set<CompilerDriver::ClassReference> RejectedClassesTable;
static Mutex* rejected_classes_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
@@ -613,20 +674,20 @@ class MethodVerifier {
// Storage for the register status we're saving for later.
UniquePtr<RegisterLine> saved_line_;
- uint32_t dex_method_idx_; // The method we're working on.
+ const uint32_t dex_method_idx_; // The method we're working on.
// Its object representation if known.
- mirror::AbstractMethod* foo_method_ GUARDED_BY(Locks::mutator_lock_);
- uint32_t method_access_flags_; // Method's access flags.
- const DexFile* dex_file_; // The dex file containing the method.
+ mirror::AbstractMethod* mirror_method_ GUARDED_BY(Locks::mutator_lock_);
+ const uint32_t method_access_flags_; // Method's access flags.
+ const DexFile* const dex_file_; // The dex file containing the method.
// The dex_cache for the declaring class of the method.
mirror::DexCache* dex_cache_ GUARDED_BY(Locks::mutator_lock_);
// The class loader for the declaring class of the method.
mirror::ClassLoader* class_loader_ GUARDED_BY(Locks::mutator_lock_);
- uint32_t class_def_idx_; // The class def index of the declaring class of the method.
- const DexFile::CodeItem* code_item_; // The code item containing the code for the method.
+ const uint32_t class_def_idx_; // The class def index of the declaring class of the method.
+ const DexFile::CodeItem* const code_item_; // The code item containing the code for the method.
+ const RegType* declaring_class_; // Lazily computed reg type of the method's declaring class.
// Instruction widths and flags, one entry per code unit.
UniquePtr<InstructionFlags[]> insn_flags_;
-
// The dex PC of a FindLocksAtDexPc request, -1 otherwise.
uint32_t interesting_dex_pc_;
// The container into which FindLocksAtDexPc should write the registers containing held locks,
diff --git a/src/verifier/reg_type.cc b/src/verifier/reg_type.cc
index 32679f6100..1c61a29cee 100644
--- a/src/verifier/reg_type.cc
+++ b/src/verifier/reg_type.cc
@@ -25,6 +25,7 @@
#include "mirror/object_array-inl.h"
#include "object_utils.h"
#include "reg_type_cache-inl.h"
+#include "scoped_thread_state_change.h"
#include <limits>
#include <sstream>
@@ -32,7 +33,6 @@
namespace art {
namespace verifier {
-static const bool kIsDebugBuild = false;
UndefinedType* UndefinedType::instance_ = NULL;
ConflictType* ConflictType::instance_ = NULL;
BooleanType* BooleanType::instance = NULL;
@@ -46,6 +46,41 @@ DoubleLoType* DoubleLoType::instance_ = NULL;
DoubleHiType* DoubleHiType::instance_ = NULL;
IntegerType* IntegerType::instance_ = NULL;
+int32_t RegType::ConstantValue() const {
+ ScopedObjectAccess soa(Thread::Current());
+ LOG(FATAL) << "Unexpected call to ConstantValue: " << *this;
+ return 0;
+}
+
+int32_t RegType::ConstantValueLo() const {
+ ScopedObjectAccess soa(Thread::Current());
+ LOG(FATAL) << "Unexpected call to ConstantValueLo: " << *this;
+ return 0;
+}
+
+int32_t RegType::ConstantValueHi() const {
+ ScopedObjectAccess soa(Thread::Current());
+ LOG(FATAL) << "Unexpected call to ConstantValueHi: " << *this;
+ return 0;
+}
+
+PrimitiveType::PrimitiveType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+ : RegType(klass, descriptor, cache_id) {
+ CHECK(klass != NULL);
+ CHECK(!descriptor.empty());
+}
+
+Cat1Type::Cat1Type(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+ : PrimitiveType(klass, descriptor, cache_id) {
+}
+
+Cat2Type::Cat2Type(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+ : PrimitiveType(klass, descriptor, cache_id) {
+}
+
std::string PreciseConstType::Dump() const {
std::stringstream result;
uint32_t val = ConstantValue();
@@ -70,36 +105,44 @@ std::string BooleanType::Dump() const {
std::string ConflictType::Dump() const {
return "Conflict";
}
+
std::string ByteType::Dump() const {
return "Byte";
}
+
std::string ShortType::Dump() const {
return "short";
}
+
std::string CharType::Dump() const {
return "Char";
}
+
std::string FloatType::Dump() const {
return "float";
}
+
std::string LongLoType::Dump() const {
return "long (Low Half)";
}
+
std::string LongHiType::Dump() const {
return "long (High Half)";
}
+
std::string DoubleLoType::Dump() const {
return "Double (Low Half)";
}
+
std::string DoubleHiType::Dump() const {
return "Double (High Half)";
}
+
std::string IntegerType::Dump() const {
return "Integer";
}
-
-DoubleHiType* DoubleHiType::CreateInstance(mirror::Class* klass, std::string& descriptor,
+DoubleHiType* DoubleHiType::CreateInstance(mirror::Class* klass, const std::string& descriptor,
uint16_t cache_id) {
if (instance_ == NULL) {
instance_ = new DoubleHiType(klass, descriptor, cache_id);
@@ -119,7 +162,7 @@ void DoubleHiType::Destroy() {
}
}
-DoubleLoType* DoubleLoType::CreateInstance(mirror::Class* klass, std::string& descriptor,
+DoubleLoType* DoubleLoType::CreateInstance(mirror::Class* klass, const std::string& descriptor,
uint16_t cache_id) {
if (instance_ == NULL) {
instance_ = new DoubleLoType(klass, descriptor, cache_id);
@@ -139,7 +182,7 @@ void DoubleLoType::Destroy() {
}
}
-LongLoType* LongLoType::CreateInstance(mirror::Class* klass, std::string& descriptor,
+LongLoType* LongLoType::CreateInstance(mirror::Class* klass, const std::string& descriptor,
uint16_t cache_id) {
if (instance_ == NULL) {
instance_ = new LongLoType(klass, descriptor, cache_id);
@@ -147,7 +190,7 @@ LongLoType* LongLoType::CreateInstance(mirror::Class* klass, std::string& descri
return instance_;
}
-LongHiType* LongHiType::CreateInstance(mirror::Class* klass, std::string& descriptor,
+LongHiType* LongHiType::CreateInstance(mirror::Class* klass, const std::string& descriptor,
uint16_t cache_id) {
if (instance_ == NULL) {
instance_ = new LongHiType(klass, descriptor, cache_id);
@@ -179,9 +222,8 @@ void LongLoType::Destroy() {
}
}
-FloatType* FloatType::CreateInstance(mirror::Class* klass, std::string& descriptor,
- uint16_t cache_id)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+FloatType* FloatType::CreateInstance(mirror::Class* klass, const std::string& descriptor,
+ uint16_t cache_id) {
if (instance_ == NULL) {
instance_ = new FloatType(klass, descriptor, cache_id);
}
@@ -199,17 +241,19 @@ void FloatType::Destroy() {
}
}
-CharType* CharType::CreateInstance(mirror::Class* klass, std::string& descriptor,
+CharType* CharType::CreateInstance(mirror::Class* klass, const std::string& descriptor,
uint16_t cache_id) {
if (instance_ == NULL) {
instance_ = new CharType(klass, descriptor, cache_id);
}
return instance_;
}
+
CharType* CharType::GetInstance() {
CHECK(instance_ != NULL);
return instance_;
}
+
void CharType::Destroy() {
if (instance_ != NULL) {
delete instance_;
@@ -217,81 +261,94 @@ void CharType::Destroy() {
}
}
-ShortType* ShortType::CreateInstance(mirror::Class* klass, std::string& descriptor,
+ShortType* ShortType::CreateInstance(mirror::Class* klass, const std::string& descriptor,
uint16_t cache_id) {
if (instance_ == NULL) {
instance_ = new ShortType(klass, descriptor, cache_id);
}
return instance_;
}
+
ShortType* ShortType::GetInstance() {
CHECK(instance_ != NULL);
return instance_;
}
+
void ShortType::Destroy() {
if (instance_ != NULL) {
delete instance_;
instance_ = NULL;
}
}
-ByteType* ByteType::CreateInstance(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+
+ByteType* ByteType::CreateInstance(mirror::Class* klass, const std::string& descriptor,
+ uint16_t cache_id) {
if (instance_ == NULL) {
instance_ = new ByteType(klass, descriptor, cache_id);
}
return instance_;
}
+
ByteType* ByteType::GetInstance() {
CHECK(instance_ != NULL);
return instance_;
}
+
void ByteType::Destroy() {
if (instance_ != NULL) {
delete instance_;
instance_ = NULL;
}
}
-IntegerType* IntegerType::CreateInstance(mirror::Class* klass, std::string& descriptor,
+
+IntegerType* IntegerType::CreateInstance(mirror::Class* klass, const std::string& descriptor,
uint16_t cache_id) {
if (instance_ == NULL) {
instance_ = new IntegerType(klass, descriptor, cache_id);
}
return instance_;
}
+
IntegerType* IntegerType::GetInstance() {
CHECK(instance_ != NULL);
return instance_;
}
+
void IntegerType::Destroy() {
if (instance_ != NULL) {
delete instance_;
instance_ = NULL;
}
}
-ConflictType* ConflictType::CreateInstance(mirror::Class* klass, std::string& descriptor,
+
+ConflictType* ConflictType::CreateInstance(mirror::Class* klass, const std::string& descriptor,
uint16_t cache_id) {
if (instance_ == NULL) {
instance_ = new ConflictType(klass, descriptor, cache_id);
}
return instance_;
}
+
ConflictType* ConflictType::GetInstance() {
CHECK(instance_ != NULL);
return instance_;
}
+
void ConflictType::Destroy() {
if (instance_ != NULL) {
delete instance_;
instance_ = NULL;
}
}
-BooleanType* BooleanType::CreateInstance(mirror::Class* klass, std::string& descriptor,
+
+BooleanType* BooleanType::CreateInstance(mirror::Class* klass, const std::string& descriptor,
uint16_t cache_id) {
if (BooleanType::instance == NULL) {
instance = new BooleanType(klass, descriptor, cache_id);
}
return BooleanType::instance;
}
+
BooleanType* BooleanType::GetInstance() {
CHECK(BooleanType::instance != NULL);
return BooleanType::instance;
@@ -307,23 +364,33 @@ void BooleanType::Destroy() {
std::string UndefinedType::Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
return "Undefined";
}
-UndefinedType* UndefinedType::CreateInstance(mirror::Class* klass, std::string& descriptor,
+
+UndefinedType* UndefinedType::CreateInstance(mirror::Class* klass, const std::string& descriptor,
uint16_t cache_id) {
if (instance_ == NULL) {
instance_ = new UndefinedType(klass, descriptor, cache_id);
}
return instance_;
}
+
UndefinedType* UndefinedType::GetInstance() {
CHECK(instance_ != NULL);
return instance_;
}
+
void UndefinedType::Destroy() {
if (instance_ != NULL) {
delete instance_;
instance_ = NULL;
}
}
+
+PreciseReferenceType::PreciseReferenceType(mirror::Class* klass, const std::string& descriptor,
+ uint16_t cache_id)
+ : RegType(klass, descriptor, cache_id) {
+ DCHECK(klass->IsInstantiable());
+}
+
std::string UnresolvedMergedType::Dump() const {
std::stringstream result;
std::set<uint16_t> types = GetMergedTypes();
@@ -338,6 +405,7 @@ std::string UnresolvedMergedType::Dump() const {
result << ")";
return result.str();
}
+
std::string UnresolvedSuperClass::Dump() const {
std::stringstream result;
uint16_t super_type_id = GetUnresolvedSuperClassChildId();
@@ -358,7 +426,7 @@ std::string UnresolvedUninitializedRefType::Dump() const {
return result.str();
}
-std::string UnresolvedUninitialisedThisRefType::Dump() const {
+std::string UnresolvedUninitializedThisRefType::Dump() const {
std::stringstream result;
result << "Unresolved And Uninitialized This Reference" << PrettyDescriptor(GetDescriptor());
return result.str();
@@ -376,13 +444,14 @@ std::string PreciseReferenceType::Dump() const {
return result.str();
}
-std::string UninitialisedReferenceType::Dump() const {
+std::string UninitializedReferenceType::Dump() const {
std::stringstream result;
result << "Uninitialized Reference" << ": " << PrettyDescriptor(GetClass());
result << " Allocation PC: " << GetAllocationPc();
return result.str();
}
-std::string UninitialisedThisReferenceType::Dump() const {
+
+std::string UninitializedThisReferenceType::Dump() const {
std::stringstream result;
result << "Uninitialized This Reference" << ": " << PrettyDescriptor(GetClass());
result << "Allocation PC: " << GetAllocationPc();
@@ -459,77 +528,8 @@ std::string ImpreciseConstHiType::Dump() const {
return result.str();
}
-BooleanType::BooleanType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
- : RegType(klass, descriptor, cache_id) {
-}
-
-ConflictType::ConflictType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
- : RegType(klass, descriptor, cache_id) {
-}
-
-ByteType::ByteType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
- : RegType(klass, descriptor, cache_id) {
-}
-
-ShortType::ShortType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
- : RegType(klass, descriptor, cache_id) {
-}
-
-CharType::CharType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
- : RegType(klass, descriptor, cache_id) {
-}
-
-IntegerType::IntegerType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
- : RegType(klass, descriptor, cache_id) {
-}
-
-ConstantType::ConstantType(uint32_t constat, uint16_t cache_id)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_): RegType(NULL, "", cache_id), constant_(constat) {
-}
-
-ReferenceType::ReferenceType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
- : RegType(klass, descriptor, cache_id) {
-}
-
-PreciseReferenceType::PreciseReferenceType(mirror::Class* klass, std::string& descriptor,
- uint16_t cache_id)
- : RegType(klass, descriptor, cache_id) {
- DCHECK(klass->IsInstantiable());
-}
-
-UnresolvedUninitialisedThisRefType::UnresolvedUninitialisedThisRefType(std::string& descriptor,
- uint16_t cache_id)
- : UninitializedType(NULL, descriptor, 0, cache_id) {
-}
-
-UnresolvedUninitializedRefType::UnresolvedUninitializedRefType( std::string& descriptor,
- uint32_t allocation_pc, uint16_t cache_id)
- : UninitializedType(NULL, descriptor, allocation_pc, cache_id) {
-}
-
-UninitialisedReferenceType::UninitialisedReferenceType(mirror::Class* klass,
- std::string& descriptor, uint32_t allocation_pc, uint16_t cache_id)
- : UninitializedType(klass, descriptor, allocation_pc, cache_id) {
-}
-
-LongHiType::LongHiType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
- : RegType(klass, descriptor, cache_id) {
-}
-
-FloatType::FloatType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
- : RegType(klass, descriptor, cache_id) {
-}
-
-DoubleLoType::DoubleLoType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
- : RegType(klass, descriptor, cache_id) {
-}
-
-DoubleHiType::DoubleHiType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
- : RegType(klass, descriptor, cache_id) {
-}
-
-LongLoType::LongLoType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
- : RegType(klass, descriptor, cache_id) {
+ConstantType::ConstantType(uint32_t constant, uint16_t cache_id)
+ : RegType(NULL, "", cache_id), constant_(constant) {
}
const RegType& UndefinedType::Merge(const RegType& incoming_type, RegTypeCache* reg_types) const
@@ -575,6 +575,17 @@ Primitive::Type RegType::GetPrimitiveType() const {
}
}
+bool UninitializedType::IsUninitializedTypes() const {
+ return true;
+}
+
+bool UninitializedType::IsNonZeroReferenceTypes() const {
+ return true;
+}
+
+bool UnresolvedType::IsNonZeroReferenceTypes() const {
+ return true;
+}
std::set<uint16_t> UnresolvedMergedType::GetMergedTypes() const {
std::pair<uint16_t, uint16_t> refs = GetTopMergedTypes();
const RegType& _left(reg_type_cache_->GetFromId(refs.first));
@@ -612,7 +623,7 @@ const RegType& RegType::GetSuperClass(RegTypeCache* cache) const {
if (super_klass != NULL) {
// A super class of a precise type isn't precise as a precise type indicates the register
// holds exactly that type.
- return cache->FromClass(super_klass, false);
+ return cache->FromClass(ClassHelper(super_klass).GetDescriptor(), super_klass, false);
} else {
return cache->Zero();
}
@@ -697,62 +708,72 @@ ImpreciseConstType::ImpreciseConstType(uint32_t constat, uint16_t cache_id)
: ConstantType(constat, cache_id) {
}
-bool RegType::IsAssignableFrom(const RegType& src) const {
- if (Equals(src)) {
+static bool AssignableFrom(const RegType& lhs, const RegType& rhs, bool strict)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ if (lhs.Equals(rhs)) {
return true;
} else {
- if (IsBoolean()) {
- return src.IsBooleanTypes();
- } else if (IsByte()) {
- return src.IsByteTypes();
- } else if (IsShort()) {
- return src.IsShortTypes();
- } else if (IsChar()) {
- return src.IsCharTypes();
- } else if (IsInteger()) {
- return src.IsIntegralTypes();
- } else if (IsFloat()) {
- return src.IsFloatTypes();
- } else if (IsLongLo()) {
- return src.IsLongTypes();
- } else if (IsDoubleLo()) {
- return src.IsDoubleTypes();
+ if (lhs.IsBoolean()) {
+ return rhs.IsBooleanTypes();
+ } else if (lhs.IsByte()) {
+ return rhs.IsByteTypes();
+ } else if (lhs.IsShort()) {
+ return rhs.IsShortTypes();
+ } else if (lhs.IsChar()) {
+ return rhs.IsCharTypes();
+ } else if (lhs.IsInteger()) {
+ return rhs.IsIntegralTypes();
+ } else if (lhs.IsFloat()) {
+ return rhs.IsFloatTypes();
+ } else if (lhs.IsLongLo()) {
+ return rhs.IsLongTypes();
+ } else if (lhs.IsDoubleLo()) {
+ return rhs.IsDoubleTypes();
} else {
- if (!IsReferenceTypes()) {
- LOG(FATAL) << "Unexpected register type in 4bleFrom: '" << src << "'";
+ CHECK(lhs.IsReferenceTypes())
+ << "Unexpected register type in IsAssignableFrom: '"
+ << lhs << "' := '" << rhs << "'";
+ if (rhs.IsZero()) {
+ return true; // All reference types can be assigned null.
+ } else if (!rhs.IsReferenceTypes()) {
+ return false; // Expect rhs to be a reference type.
+ } else if (lhs.IsJavaLangObject()) {
+ return true; // All reference types can be assigned to Object.
+ } else if (!strict && !lhs.IsUnresolvedTypes() && lhs.GetClass()->IsInterface()) {
+ // If we're not strict allow assignment to any interface, see comment in ClassJoin.
+ return true;
+ } else if (lhs.IsJavaLangObjectArray()) {
+ return rhs.IsObjectArrayTypes(); // All reference arrays may be assigned to Object[]
+ } else if (lhs.HasClass() && rhs.HasClass() &&
+ lhs.GetClass()->IsAssignableFrom(rhs.GetClass())) {
+ // We're assignable from the Class point-of-view.
+ return true;
+ } else {
+ // Unresolved types are only assignable for null and equality.
+ return false;
}
- if (src.IsZero()) {
- return true; // all reference types can be assigned null
- } else if (!src.IsReferenceTypes()) {
- return false; // expect src to be a reference type
- } else if (IsJavaLangObject()) {
- return true; // all reference types can be assigned to Object
- } else if (!IsUnresolvedTypes() && GetClass()->IsInterface()) {
- return true; // We allow assignment to any interface, see comment in ClassJoin
- } else if (IsJavaLangObjectArray()) {
- return src.IsObjectArrayTypes(); // All reference arrays may be assigned to Object[]
- } else if (!IsUnresolvedTypes() && !src.IsUnresolvedTypes() &&
- GetClass()->IsAssignableFrom(src.GetClass())) {
- // We're assignable from the Class point-of-view
- return true;
- } else if (IsUnresolvedTypes()) {
- // Unresolved types are only assignable for null, Object and equality.
- return (src.IsZero() || src.IsJavaLangObject());
- } else {
- return false;
- }
}
}
}
+bool RegType::IsAssignableFrom(const RegType& src) const {
+ return AssignableFrom(*this, src, false);
+}
+
+bool RegType::IsStrictlyAssignableFrom(const RegType& src) const {
+ return AssignableFrom(*this, src, true);
+}
+
int32_t ConstantType::ConstantValue() const {
DCHECK(IsConstantTypes());
return constant_;
}
+
int32_t ConstantType::ConstantValueLo() const {
DCHECK(IsConstantLo());
return constant_;
}
+
int32_t ConstantType::ConstantValueHi() const {
if (IsConstantHi() || IsPreciseConstantHi() || IsImpreciseConstantHi()) {
return constant_;
@@ -761,6 +782,7 @@ int32_t ConstantType::ConstantValueHi() const {
return 0;
}
}
+
static const RegType& SelectNonConstant(const RegType& a, const RegType& b) {
return a.IsConstant() ? b : a;
}
@@ -884,7 +906,7 @@ const RegType& RegType::Merge(const RegType& incoming_type, RegTypeCache* reg_ty
} else if (c2 == join_class && !incoming_type.IsPreciseReference()) {
return incoming_type;
} else {
- return reg_types->FromClass(join_class, false);
+ return reg_types->FromClass(ClassHelper(join_class).GetDescriptor(), join_class, false);
}
}
} else {
@@ -949,33 +971,22 @@ void RegType::CheckInvariants() const {
CHECK(descriptor_.empty()) << *this;
CHECK(klass_ == NULL) << *this;
}
+ if (klass_ != NULL) {
+ CHECK(!descriptor_.empty()) << *this;
+ }
}
-UninitializedType::UninitializedType(mirror::Class* klass, std::string& descriptor,
- uint32_t allocation_pc, uint16_t cache_id)
- : RegType(klass, descriptor, cache_id), allocation_pc_(allocation_pc) {
-}
-
-void UninitializedType::CheckInvariants() const {
- CHECK_EQ(allocation_pc_, 0U) << *this;
-}
-
-void UninitialisedThisReferenceType::CheckInvariants() const {
- UninitializedType::CheckInvariants();
-}
-
-UninitialisedThisReferenceType::UninitialisedThisReferenceType(mirror::Class* klass,
- std::string& descriptor, uint16_t cache_id) : UninitializedType(klass, descriptor, 0, cache_id) {
+void UninitializedThisReferenceType::CheckInvariants() const {
+ CHECK_EQ(GetAllocationPc(), 0U) << *this;
}
-void UnresolvedUninitialisedThisRefType::CheckInvariants() const {
- UninitializedType::CheckInvariants();
+void UnresolvedUninitializedThisRefType::CheckInvariants() const {
+ CHECK_EQ(GetAllocationPc(), 0U) << *this;
CHECK(!descriptor_.empty()) << *this;
CHECK(klass_ == NULL) << *this;
}
void UnresolvedUninitializedRefType::CheckInvariants() const {
- UninitializedType::CheckInvariants();
CHECK(!descriptor_.empty()) << *this;
CHECK(klass_ == NULL) << *this;
}
diff --git a/src/verifier/reg_type.h b/src/verifier/reg_type.h
index 7c4253604c..9ac0ecac8a 100644
--- a/src/verifier/reg_type.h
+++ b/src/verifier/reg_type.h
@@ -18,6 +18,7 @@
#define ART_SRC_VERIFIER_REG_TYPE_H_
#include "base/macros.h"
+#include "globals.h"
#include "primitive.h"
#include "jni.h"
@@ -39,105 +40,43 @@ class RegTypeCache;
*/
class RegType {
public:
- // The high half that corresponds to this low half
- const RegType& HighHalf(RegTypeCache* cache) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- inline virtual bool IsUndefined() const {
- return false;
- }
- inline virtual bool IsConflict() const {
- return false;
- }
- inline virtual bool IsBoolean() const {
- return false;
- }
- inline virtual bool IsByte() const {
- return false;
- }
- inline virtual bool IsChar() const {
- return false;
- }
- inline virtual bool IsShort() const {
- return false;
- }
- inline virtual bool IsInteger() const {
- return false;
- }
- inline virtual bool IsLongLo() const {
- return false;
- }
- inline virtual bool IsLongHi() const {
- return false;
- }
- inline virtual bool IsFloat() const {
- return false;
- }
- inline virtual bool IsDouble() const {
- return false;
- }
- inline virtual bool IsDoubleLo() const {
- return false;
- }
- inline virtual bool IsDoubleHi() const {
- return false;
- }
- inline virtual bool IsUnresolvedReference() const {
- return false;
- }
- inline virtual bool IsUninitializedReference() const {
- return false;
- }
- inline virtual bool IsUninitializedThisReference() const {
- return false;
- }
- inline virtual bool IsUnresolvedAndUninitializedReference() const {
- return false;
- }
- inline virtual bool IsUnresolvedAndUninitializedThisReference() const {
- return false;
- }
- inline virtual bool IsUnresolvedMergedReference() const {
- return false;
- }
- inline virtual bool IsUnresolvedSuperClass() const {
- return false;
- }
- inline virtual bool IsReference() const {
- return false;
- }
- inline virtual bool IsPreciseReference() const {
- return false;
- }
- inline virtual bool IsPreciseConstant() const {
- return false;
- }
- inline virtual bool IsPreciseConstantLo() const {
- return false;
- }
- inline virtual bool IsPreciseConstantHi() const {
- return false;
- }
- inline virtual bool IsImpreciseConstantLo() const {
- return false;
- }
- inline virtual bool IsImpreciseConstantHi() const {
- return false;
- }
- virtual bool IsImpreciseConstant() const {
- return false;
- }
-
- inline virtual bool IsConstantTypes() const {
- return false;
- }
+ virtual bool IsUndefined() const { return false; }
+ virtual bool IsConflict() const { return false; }
+ virtual bool IsBoolean() const { return false; }
+ virtual bool IsByte() const { return false; }
+ virtual bool IsChar() const { return false; }
+ virtual bool IsShort() const { return false; }
+ virtual bool IsInteger() const { return false; }
+ virtual bool IsLongLo() const { return false; }
+ virtual bool IsLongHi() const { return false; }
+ virtual bool IsFloat() const { return false; }
+ virtual bool IsDouble() const { return false; }
+ virtual bool IsDoubleLo() const { return false; }
+ virtual bool IsDoubleHi() const { return false; }
+ virtual bool IsUnresolvedReference() const { return false; }
+ virtual bool IsUninitializedReference() const { return false; }
+ virtual bool IsUninitializedThisReference() const { return false; }
+ virtual bool IsUnresolvedAndUninitializedReference() const { return false; }
+ virtual bool IsUnresolvedAndUninitializedThisReference() const { return false; }
+ virtual bool IsUnresolvedMergedReference() const { return false; }
+ virtual bool IsUnresolvedSuperClass() const { return false; }
+ virtual bool IsReference() const { return false; }
+ virtual bool IsPreciseReference() const { return false; }
+ virtual bool IsPreciseConstant() const { return false; }
+ virtual bool IsPreciseConstantLo() const { return false; }
+ virtual bool IsPreciseConstantHi() const { return false; }
+ virtual bool IsImpreciseConstantLo() const { return false; }
+ virtual bool IsImpreciseConstantHi() const { return false; }
+ virtual bool IsImpreciseConstant() const { return false; }
+ virtual bool IsConstantTypes() const { return false; }
bool IsConstant() const {
- return (IsPreciseConstant() || IsImpreciseConstant());
+ return IsPreciseConstant() || IsImpreciseConstant();
}
bool IsConstantLo() const {
- return (IsPreciseConstantLo() || IsImpreciseConstantLo());
+ return IsPreciseConstantLo() || IsImpreciseConstantLo();
}
bool IsPrecise() const {
- return (IsPreciseConstantLo() || IsPreciseConstant() ||
- IsPreciseConstantHi());
+ return IsPreciseConstantLo() || IsPreciseConstant() || IsPreciseConstantHi();
}
bool IsLongConstant() const {
return IsConstantLo();
@@ -148,11 +87,7 @@ class RegType {
bool IsLongConstantHigh() const {
return IsConstantHi();
}
- bool IsUninitializedTypes() const {
- return IsUninitializedReference() || IsUninitializedThisReference() ||
- IsUnresolvedAndUninitializedReference() ||
- IsUnresolvedAndUninitializedThisReference();
- }
+ virtual bool IsUninitializedTypes() const { return false; }
bool IsUnresolvedTypes() const {
return IsUnresolvedReference() || IsUnresolvedAndUninitializedReference() ||
IsUnresolvedAndUninitializedThisReference() ||
@@ -170,7 +105,7 @@ class RegType {
bool IsLongOrDoubleTypes() const {
return IsLowHalf();
}
- // Check this is the low half, and that type_h is its matching high-half
+ // Check this is the low half, and that type_h is its matching high-half.
inline bool CheckWidePair(const RegType& type_h) const {
if (IsLowHalf()) {
return ((IsPreciseConstantLo() && type_h.IsPreciseConstantHi()) ||
@@ -182,37 +117,36 @@ class RegType {
}
return false;
}
+ // The high half that corresponds to this low half
+ const RegType& HighHalf(RegTypeCache* cache) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
bool IsConstantBoolean() const {
return IsConstant() && (ConstantValue() >= 0) && (ConstantValue() <= 1);
}
- inline virtual bool IsConstantChar() const {
+ virtual bool IsConstantChar() const {
return false;
}
- inline virtual bool IsConstantByte() const {
+ virtual bool IsConstantByte() const {
return false;
}
- inline virtual bool IsConstantShort() const {
+ virtual bool IsConstantShort() const {
return false;
}
- inline virtual bool IsOne() const {
+ virtual bool IsOne() const {
return false;
}
- inline virtual bool IsZero() const {
+ virtual bool IsZero() const {
return false;
}
bool IsReferenceTypes() const {
return IsNonZeroReferenceTypes() || IsZero();
}
- bool IsNonZeroReferenceTypes() const {
- return IsReference() || IsPreciseReference() ||
- IsUninitializedReference() || IsUninitializedThisReference() ||
- IsUnresolvedReference() || IsUnresolvedAndUninitializedReference() ||
- IsUnresolvedAndUninitializedThisReference() ||
- IsUnresolvedMergedReference() || IsUnresolvedSuperClass();
+ virtual bool IsNonZeroReferenceTypes() const {
+ return false;
}
bool IsCategory1Types() const {
- return (IsChar() || IsInteger() || IsFloat() || IsConstant() || IsByte() ||
- IsShort() || IsBoolean() );
+ return IsChar() || IsInteger() || IsFloat() || IsConstant() || IsByte() || IsShort() ||
+ IsBoolean();
}
bool IsCategory2Types() const {
return IsLowHalf(); // Don't expect explicit testing of high halves
@@ -230,20 +164,12 @@ class RegType {
return IsChar() || IsBooleanTypes() || IsConstantChar();
}
bool IsIntegralTypes() const {
- return (IsInteger() || IsConstant() || IsByte() || IsShort() || IsChar() || IsBoolean() );
- }
- inline virtual int32_t ConstantValue() const {
- DCHECK(IsConstant());
- return -1;
- }
- inline virtual int32_t ConstantValueLo() const {
- DCHECK(IsConstantLo());
- return -1;
- }
- inline virtual int32_t ConstantValueHi() const {
- DCHECK(IsConstantHi());
- return -1;
+ return IsInteger() || IsConstant() || IsByte() || IsShort() || IsChar() || IsBoolean();
}
+ // Give the constant value encoded, but this shouldn't be called in the general case.
+ virtual int32_t ConstantValue() const;
+ virtual int32_t ConstantValueLo() const;
+ virtual int32_t ConstantValueHi() const;
bool IsArrayIndexTypes() const {
return IsIntegralTypes();
}
@@ -265,12 +191,11 @@ class RegType {
bool IsDoubleHighTypes() const {
return (IsDoubleHi() || IsPreciseConstantHi() || IsImpreciseConstantHi());
}
- inline virtual bool IsLong() const {
+ virtual bool IsLong() const {
return false;
}
- bool HasClass() const {
- return IsReference() || IsPreciseReference() || IsUninitializedReference() ||
- IsUninitializedThisReference();
+ virtual bool HasClass() const {
+ return false;
}
bool IsJavaLangObject() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
bool IsArrayTypes() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -279,210 +204,286 @@ class RegType {
bool IsJavaLangObjectArray() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
bool IsInstantiableTypes() const;
const std::string& GetDescriptor() const {
- DCHECK(IsUnresolvedTypes() && !IsUnresolvedMergedReference() && !IsUnresolvedSuperClass());
+ DCHECK(HasClass() || (IsUnresolvedTypes() && !IsUnresolvedMergedReference() &&
+ !IsUnresolvedSuperClass()));
return descriptor_;
}
+ mirror::Class* GetClass() const {
+ DCHECK(!IsUnresolvedReference());
+ DCHECK(klass_ != NULL);
+ DCHECK(HasClass());
+ return klass_;
+ }
uint16_t GetId() const {
return cache_id_;
}
const RegType& GetSuperClass(RegTypeCache* cache) const
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
virtual std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) = 0;
+
// Can this type access other?
bool CanAccess(const RegType& other) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
// Can this type access a member with the given properties?
bool CanAccessMember(mirror::Class* klass, uint32_t access_flags) const
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
// Can this type be assigned by src?
- bool IsAssignableFrom(const RegType& src) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ // Note: Object and interface types may always be assigned to one another, see comment on
+ // ClassJoin.
+ bool IsAssignableFrom(const RegType& src) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ // Can this type be assigned by src? Variant of IsAssignableFrom that doesn't allow assignment to
+ // an interface from an Object.
+ bool IsStrictlyAssignableFrom(const RegType& src) const
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ // Are these RegTypes the same?
bool Equals(const RegType& other) const {
return GetId() == other.GetId();
}
+
// Compute the merge of this register from one edge (path) with incoming_type from another.
virtual const RegType& Merge(const RegType& incoming_type, RegTypeCache* reg_types) const
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- mirror::Class* GetClass() const {
- DCHECK(!IsUnresolvedReference());
- DCHECK(klass_ != NULL);
- DCHECK(HasClass());
- return klass_;
- }
- /*
- * A basic Join operation on classes. For a pair of types S and T the Join, written S v T = J, is
- * S <: J, T <: J and for-all U such that S <: U, T <: U then J <: U. That is J is the parent of
- * S and T such that there isn't a parent of both S and T that isn't also the parent of J (ie J
- * is the deepest (lowest upper bound) parent of S and T).
- *
- * This operation applies for regular classes and arrays, however, for interface types there needn't
- * be a partial ordering on the types. We could solve the problem of a lack of a partial order by
- * introducing sets of types, however, the only operation permissible on an interface is
- * invoke-interface. In the tradition of Java verifiers [1] we defer the verification of interface
- * types until an invoke-interface call on the interface typed reference at runtime and allow
- * the perversion of Object being assignable to an interface type (note, however, that we don't
- * allow assignment of Object or Interface to any concrete class and are therefore type safe).
- *
- * [1] Java bytecode verification: algorithms and formalizations, Xavier Leroy
- */
+ /*
+ * A basic Join operation on classes. For a pair of types S and T the Join, written S v T = J, is
+ * S <: J, T <: J and for-all U such that S <: U, T <: U then J <: U. That is J is the parent of
+ * S and T such that there isn't a parent of both S and T that isn't also the parent of J (ie J
+ * is the deepest (lowest upper bound) parent of S and T).
+ *
+ * This operation applies for regular classes and arrays, however, for interface types there
+ * needn't be a partial ordering on the types. We could solve the problem of a lack of a partial
+ * order by introducing sets of types, however, the only operation permissible on an interface is
+ * invoke-interface. In the tradition of Java verifiers [1] we defer the verification of interface
+ * types until an invoke-interface call on the interface typed reference at runtime and allow
+ * the perversion of Object being assignable to an interface type (note, however, that we don't
+ * allow assignment of Object or Interface to any concrete class and are therefore type safe).
+ *
+ * [1] Java bytecode verification: algorithms and formalizations, Xavier Leroy
+ */
static mirror::Class* ClassJoin(mirror::Class* s, mirror::Class* t)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- RegType(mirror::Class* klass, std::string descriptor, uint16_t cache_id)
+
+ virtual ~RegType() {}
+
+ protected:
+ RegType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
: descriptor_(descriptor), klass_(klass), cache_id_(cache_id) {
+ if (kIsDebugBuild) {
+ CheckInvariants();
+ }
}
- inline virtual ~RegType() {
- }
- virtual void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- friend class RegTypeCache;
- protected:
+ void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+
const std::string descriptor_;
- mirror::Class* klass_;
+ mirror::Class* const klass_;
const uint16_t cache_id_;
+ friend class RegTypeCache;
+
DISALLOW_COPY_AND_ASSIGN(RegType);
};
+// Bottom type.
class ConflictType : public RegType {
public:
bool IsConflict() const {
return true;
}
+
std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- static ConflictType* CreateInstance(mirror::Class* klass, std::string& descriptor,
- uint16_t cache_id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ // Get the singleton Conflict instance.
static ConflictType* GetInstance();
+
+ // Create the singleton instance.
+ static ConflictType* CreateInstance(mirror::Class* klass, const std::string& descriptor,
+ uint16_t cache_id)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ // Destroy the singleton instance.
static void Destroy();
private:
- ConflictType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ ConflictType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+ : RegType(klass, descriptor, cache_id) {
+ }
+
static ConflictType* instance_;
};
+// A variant of the bottom type used to specify an undefined value in the incoming registers.
+// Merging with UndefinedType yields ConflictType which is the true bottom.
class UndefinedType : public RegType {
public:
bool IsUndefined() const {
return true;
}
+
std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- static UndefinedType* CreateInstance(mirror::Class* klass, std::string& descriptor,
+
+ // Get the singleton Undefined instance.
+ static UndefinedType* GetInstance();
+
+ // Create the singleton instance.
+ static UndefinedType* CreateInstance(mirror::Class* klass, const std::string& descriptor,
uint16_t cache_id)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- static UndefinedType* GetInstance();
+
+ // Destroy the singleton instance.
static void Destroy();
private:
- UndefinedType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
+ UndefinedType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
: RegType(klass, descriptor, cache_id) {
}
+
virtual const RegType& Merge(const RegType& incoming_type, RegTypeCache* reg_types) const
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
static UndefinedType* instance_;
};
-class IntegerType : public RegType {
+class PrimitiveType : public RegType {
+ public:
+ PrimitiveType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+};
+
+class Cat1Type : public PrimitiveType {
+ public:
+ Cat1Type(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+};
+
+class IntegerType : public Cat1Type {
public:
bool IsInteger() const {
return true;
}
std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- static IntegerType* CreateInstance(mirror::Class* klass, std::string& descriptor,
+ static IntegerType* CreateInstance(mirror::Class* klass, const std::string& descriptor,
uint16_t cache_id)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
static IntegerType* GetInstance();
static void Destroy();
private:
- IntegerType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ IntegerType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+ : Cat1Type(klass, descriptor, cache_id) {
+ }
static IntegerType* instance_;
};
-class BooleanType : public RegType {
+class BooleanType : public Cat1Type {
public:
bool IsBoolean() const {
return true;
}
std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- static BooleanType* CreateInstance(mirror::Class* klass, std::string& descriptor,
+ static BooleanType* CreateInstance(mirror::Class* klass, const std::string& descriptor,
uint16_t cache_id)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
static BooleanType* GetInstance();
static void Destroy();
private:
- BooleanType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ BooleanType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+ : Cat1Type(klass, descriptor, cache_id) {
+ }
+
static BooleanType* instance;
};
-class ByteType : public RegType {
+class ByteType : public Cat1Type {
public:
bool IsByte() const {
return true;
}
std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- static ByteType* CreateInstance(mirror::Class* klass, std::string& descriptor,
+ static ByteType* CreateInstance(mirror::Class* klass, const std::string& descriptor,
uint16_t cache_id)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
static ByteType* GetInstance();
static void Destroy();
private:
- ByteType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ ByteType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+ : Cat1Type(klass, descriptor, cache_id) {
+ }
static ByteType* instance_;
};
-class ShortType : public RegType {
+class ShortType : public Cat1Type {
public:
bool IsShort() const {
return true;
}
std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- static ShortType* CreateInstance(mirror::Class* klass, std::string& descriptor,
+ static ShortType* CreateInstance(mirror::Class* klass, const std::string& descriptor,
uint16_t cache_id)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
static ShortType* GetInstance();
static void Destroy();
private:
- ShortType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ ShortType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+ : Cat1Type(klass, descriptor, cache_id) {
+ }
static ShortType* instance_;
};
-class CharType : public RegType {
+class CharType : public Cat1Type {
public:
bool IsChar() const {
return true;
}
std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- static CharType* CreateInstance(mirror::Class* klass, std::string& descriptor,
+ static CharType* CreateInstance(mirror::Class* klass, const std::string& descriptor,
uint16_t cache_id)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
static CharType* GetInstance();
static void Destroy();
private:
- CharType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ CharType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+ : Cat1Type(klass, descriptor, cache_id) {
+ }
static CharType* instance_;
};
-class FloatType : public RegType {
+class FloatType : public Cat1Type {
public:
bool IsFloat() const {
return true;
}
std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- static FloatType* CreateInstance(mirror::Class* klass, std::string& descriptor,
+ static FloatType* CreateInstance(mirror::Class* klass, const std::string& descriptor,
uint16_t cache_id)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
static FloatType* GetInstance();
static void Destroy();
private:
- FloatType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ FloatType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+ : Cat1Type(klass, descriptor, cache_id) {
+ }
static FloatType* instance_;
};
-class LongLoType : public RegType {
+class Cat2Type : public PrimitiveType {
+ public:
+ Cat2Type(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+};
+
+class LongLoType : public Cat2Type {
public:
std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
bool IsLongLo() const {
@@ -491,35 +492,39 @@ class LongLoType : public RegType {
bool IsLong() const {
return true;
}
- static LongLoType* CreateInstance(mirror::Class* klass, std::string& descriptor,
+ static LongLoType* CreateInstance(mirror::Class* klass, const std::string& descriptor,
uint16_t cache_id)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
static LongLoType* GetInstance();
static void Destroy();
private:
- LongLoType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ LongLoType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+ : Cat2Type(klass, descriptor, cache_id) {
+ }
static LongLoType* instance_;
};
-class LongHiType : public RegType {
+class LongHiType : public Cat2Type {
public:
std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
bool IsLongHi() const {
return true;
}
- static LongHiType* CreateInstance(mirror::Class* klass, std::string& descriptor,
+ static LongHiType* CreateInstance(mirror::Class* klass, const std::string& descriptor,
uint16_t cache_id)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
static LongHiType* GetInstance();
static void Destroy();
private:
- LongHiType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ LongHiType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+ : Cat2Type(klass, descriptor, cache_id) {
+ }
static LongHiType* instance_;
};
-class DoubleLoType : public RegType {
+class DoubleLoType : public Cat2Type {
public:
std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
bool IsDoubleLo() const {
@@ -528,31 +533,35 @@ class DoubleLoType : public RegType {
bool IsDouble() const {
return true;
}
- static DoubleLoType* CreateInstance(mirror::Class* klass, std::string& descriptor,
+ static DoubleLoType* CreateInstance(mirror::Class* klass, const std::string& descriptor,
uint16_t cache_id)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
static DoubleLoType* GetInstance();
static void Destroy();
private:
- DoubleLoType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ DoubleLoType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+ : Cat2Type(klass, descriptor, cache_id) {
+ }
static DoubleLoType* instance_;
};
-class DoubleHiType : public RegType {
+class DoubleHiType : public Cat2Type {
public:
std::string Dump() const;
virtual bool IsDoubleHi() const {
return true;
}
- static DoubleHiType* CreateInstance(mirror::Class* klass, std::string& descriptor,
+ static DoubleHiType* CreateInstance(mirror::Class* klass, const std::string& descriptor,
uint16_t cache_id)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
static DoubleHiType* GetInstance();
static void Destroy();
private:
- DoubleHiType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ DoubleHiType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+ : Cat2Type(klass, descriptor, cache_id) {
+ }
static DoubleHiType* instance_;
};
@@ -560,9 +569,6 @@ class ConstantType : public RegType {
public:
ConstantType(uint32_t constat, uint16_t cache_id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- inline virtual ~ConstantType() {
- }
- const uint32_t constant_;
// If this is a 32-bit constant, what is the value? This value may be imprecise in which case
// the value represents part of the integer range of values that may be held in the register.
virtual int32_t ConstantValue() const;
@@ -590,7 +596,10 @@ class ConstantType : public RegType {
ConstantValue() >= std::numeric_limits<jshort>::min() &&
ConstantValue() <= std::numeric_limits<jshort>::max();
}
- inline virtual bool IsConstantTypes() const { return true; }
+ virtual bool IsConstantTypes() const { return true; }
+
+ private:
+ const uint32_t constant_;
};
class PreciseConstType : public ConstantType {
@@ -662,147 +671,254 @@ class ImpreciseConstHiType : public ConstantType {
std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
};
+// Common parent of all uninitialized types. Uninitialized types are created by "new" dex
+// instructions and must be passed to a constructor.
class UninitializedType : public RegType {
public:
- UninitializedType(mirror::Class* klass, std::string& descriptor, uint32_t allocation_pc,
- uint16_t cache_id);
- inline virtual ~UninitializedType() {
+ UninitializedType(mirror::Class* klass, const std::string& descriptor, uint32_t allocation_pc,
+ uint16_t cache_id)
+ : RegType(klass, descriptor, cache_id), allocation_pc_(allocation_pc) {
}
+ bool IsUninitializedTypes() const;
+ bool IsNonZeroReferenceTypes() const;
+
uint32_t GetAllocationPc() const {
DCHECK(IsUninitializedTypes());
return allocation_pc_;
}
- virtual void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
private:
const uint32_t allocation_pc_;
};
-class UninitialisedReferenceType : public UninitializedType {
+// Similar to ReferenceType but not yet having been passed to a constructor.
+class UninitializedReferenceType : public UninitializedType {
public:
- UninitialisedReferenceType(mirror::Class* klass, std::string& descriptor, uint32_t allocation_pc,
- uint16_t cache_id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ UninitializedReferenceType(mirror::Class* klass, const std::string& descriptor,
+ uint32_t allocation_pc, uint16_t cache_id)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+ : UninitializedType(klass, descriptor, allocation_pc, cache_id) {
+ }
bool IsUninitializedReference() const {
return true;
}
+
+ bool HasClass() const {
+ return true;
+ }
+
std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
};
+// Similar to UnresolvedReferenceType but not yet having been passed to a constructor.
class UnresolvedUninitializedRefType : public UninitializedType {
public:
- UnresolvedUninitializedRefType(std::string& descriptor, uint32_t allocation_pc,
- uint16_t cache_id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ UnresolvedUninitializedRefType(const std::string& descriptor, uint32_t allocation_pc,
+ uint16_t cache_id)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+ : UninitializedType(NULL, descriptor, allocation_pc, cache_id) {
+ if (kIsDebugBuild) {
+ CheckInvariants();
+ }
+ }
+
bool IsUnresolvedAndUninitializedReference() const {
return true;
}
+
std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ private:
+ void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
};
-class UninitialisedThisReferenceType : public UninitializedType {
+// Similar to UninitializedReferenceType but special case for the this argument of a constructor.
+class UninitializedThisReferenceType : public UninitializedType {
public:
- UninitialisedThisReferenceType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- inline virtual bool IsUninitializedThisReference() const {
+ UninitializedThisReferenceType(mirror::Class* klass, const std::string& descriptor,
+ uint16_t cache_id)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+ : UninitializedType(klass, descriptor, 0, cache_id) {
+ if (kIsDebugBuild) {
+ CheckInvariants();
+ }
+ }
+
+ virtual bool IsUninitializedThisReference() const {
return true;
}
+
+ bool HasClass() const {
+ return true;
+ }
+
+ std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ private:
+ void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
};
-class UnresolvedUninitialisedThisRefType : public UninitializedType {
+class UnresolvedUninitializedThisRefType : public UninitializedType {
public:
- UnresolvedUninitialisedThisRefType(std::string& descriptor, uint16_t cache_id)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ UnresolvedUninitializedThisRefType(const std::string& descriptor, uint16_t cache_id)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+ : UninitializedType(NULL, descriptor, 0, cache_id) {
+ if (kIsDebugBuild) {
+ CheckInvariants();
+ }
+ }
+
bool IsUnresolvedAndUninitializedThisReference() const {
return true;
}
+
+ std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ private:
+ void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
};
+// A type of register holding a reference to an Object of type GetClass or a sub-class.
class ReferenceType : public RegType {
public:
- ReferenceType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ ReferenceType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+ : RegType(klass, descriptor, cache_id) {
+ }
+
bool IsReference() const {
return true;
}
+
+ bool IsNonZeroReferenceTypes() const {
+ return true;
+ }
+
+ bool HasClass() const {
+ return true;
+ }
+
std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
};
+// A type of register holding a reference to an Object of type GetClass and only an object of that
+// type.
class PreciseReferenceType : public RegType {
public:
- PreciseReferenceType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
+ PreciseReferenceType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
bool IsPreciseReference() const {
return true;
}
+
+ bool IsNonZeroReferenceTypes() const {
+ return true;
+ }
+
+ bool HasClass() const {
+ return true;
+ }
+
+ std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
};
-class UnresolvedReferenceType : public RegType {
+// Common parent of unresolved types.
+class UnresolvedType : public RegType {
public:
- UnresolvedReferenceType(std::string& descriptor, uint16_t cache_id)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) : RegType(NULL, descriptor, cache_id) {
+ UnresolvedType(const std::string& descriptor, uint16_t cache_id)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) : RegType(NULL, descriptor, cache_id) {
}
- std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ bool IsNonZeroReferenceTypes() const;
+};
+
+// Similar to ReferenceType except the Class couldn't be loaded. Assignability and other tests made
+// of this type must be conservative.
+class UnresolvedReferenceType : public UnresolvedType {
+ public:
+ UnresolvedReferenceType(const std::string& descriptor, uint16_t cache_id)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) : UnresolvedType(descriptor, cache_id) {
+ if (kIsDebugBuild) {
+ CheckInvariants();
+ }
+ }
+
bool IsUnresolvedReference() const {
return true;
}
+
+ std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ private:
+ void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
};
-class UnresolvedSuperClass : public RegType {
+// Type representing the super-class of an unresolved type.
+class UnresolvedSuperClass : public UnresolvedType {
public:
UnresolvedSuperClass(uint16_t child_id, RegTypeCache* reg_type_cache, uint16_t cache_id)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
- : RegType(NULL, "", cache_id), unresolved_child_id_(child_id),
+ : UnresolvedType("", cache_id), unresolved_child_id_(child_id),
reg_type_cache_(reg_type_cache) {
+ if (kIsDebugBuild) {
+ CheckInvariants();
+ }
}
+
bool IsUnresolvedSuperClass() const {
return true;
}
+
uint16_t GetUnresolvedSuperClassChildId() const {
DCHECK(IsUnresolvedSuperClass());
return static_cast<uint16_t>(unresolved_child_id_ & 0xFFFF);
}
- void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
private:
+ void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
const uint16_t unresolved_child_id_;
const RegTypeCache* const reg_type_cache_;
};
-class UnresolvedMergedType : public RegType {
+// A merge of two unresolved types. If the types were resolved this may be Conflict or another
+// known ReferenceType.
+class UnresolvedMergedType : public UnresolvedType {
public:
- UnresolvedMergedType(uint16_t left_id, uint16_t right_id, const RegTypeCache* reg_type_cache, uint16_t cache_id)
+ UnresolvedMergedType(uint16_t left_id, uint16_t right_id, const RegTypeCache* reg_type_cache,
+ uint16_t cache_id)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
- : RegType(NULL, "", cache_id), reg_type_cache_(reg_type_cache) ,merged_types_(left_id, right_id) {
+ : UnresolvedType("", cache_id), reg_type_cache_(reg_type_cache) ,merged_types_(left_id, right_id) {
+ if (kIsDebugBuild) {
+ CheckInvariants();
+ }
}
+
// The top of a tree of merged types.
std::pair<uint16_t, uint16_t> GetTopMergedTypes() const {
DCHECK(IsUnresolvedMergedReference());
return merged_types_;
}
+
// The complete set of merged types.
std::set<uint16_t> GetMergedTypes() const;
+
bool IsUnresolvedMergedReference() const {
return true;
}
- void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
private:
+ void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
const RegTypeCache* const reg_type_cache_;
const std::pair<uint16_t, uint16_t> merged_types_;
};
std::ostream& operator<<(std::ostream& os, const RegType& rhs)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
} // namespace verifier
} // namespace art
diff --git a/src/verifier/reg_type_cache-inl.h b/src/verifier/reg_type_cache-inl.h
index f6b0056536..42474d1849 100644
--- a/src/verifier/reg_type_cache-inl.h
+++ b/src/verifier/reg_type_cache-inl.h
@@ -24,7 +24,7 @@
namespace art {
namespace verifier {
template <class Type>
-Type* RegTypeCache::CreatePrimitiveTypeInstance(std::string descriptor) {
+Type* RegTypeCache::CreatePrimitiveTypeInstance(const std::string& descriptor) {
mirror::Class* klass = NULL;
// Try loading the class from linker.
if (!descriptor.empty()) {
@@ -35,6 +35,12 @@ Type* RegTypeCache::CreatePrimitiveTypeInstance(std::string descriptor) {
return entry;
}
+inline const art::verifier::RegType& RegTypeCache::GetFromId(uint16_t id) const {
+ DCHECK_LT(id, entries_.size());
+ RegType* result = entries_[id];
+ DCHECK(result != NULL);
+ return *result;
+}
} // namespace verifier
} // namespace art
#endif // ART_SRC_VERIFIER_REG_TYPE_CACHE_INL_H_
diff --git a/src/verifier/reg_type_cache.cc b/src/verifier/reg_type_cache.cc
index e914d1e679..6013250835 100644
--- a/src/verifier/reg_type_cache.cc
+++ b/src/verifier/reg_type_cache.cc
@@ -24,13 +24,24 @@
namespace art {
namespace verifier {
+
bool RegTypeCache::primitive_initialized_ = false;
uint16_t RegTypeCache::primitive_start_ = 0;
uint16_t RegTypeCache::primitive_count_ = 0;
static bool MatchingPrecisionForClass(RegType* entry, bool precise)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- return (entry->IsPreciseReference() == precise) || (entry->GetClass()->IsFinal() && !precise);
+ if (entry->IsPreciseReference() == precise) {
+ // We were or weren't looking for a precise reference and we found what we need.
+ return true;
+ } else {
+ if (!precise && entry->GetClass()->CannotBeAssignedFromOtherTypes()) {
+ // We weren't looking for a precise reference, as we're looking up based on a descriptor, but
+ // we found a matching entry based on the descriptor. Return the precise entry in that case.
+ return true;
+ }
+ return false;
+ }
}
void RegTypeCache::FillPrimitiveTypes() {
@@ -49,9 +60,10 @@ void RegTypeCache::FillPrimitiveTypes() {
DCHECK_EQ(entries_.size(), primitive_count_);
}
-const RegType& RegTypeCache::FromDescriptor(mirror::ClassLoader* loader, const char* descriptor, bool precise) {
- CHECK(RegTypeCache::primitive_initialized_);
- if (std::string(descriptor).length() == 1) {
+const RegType& RegTypeCache::FromDescriptor(mirror::ClassLoader* loader, const char* descriptor,
+ bool precise) {
+ DCHECK(RegTypeCache::primitive_initialized_);
+ if (descriptor[1] == '\0') {
switch (descriptor[0]) {
case 'Z':
return Boolean();
@@ -80,15 +92,7 @@ const RegType& RegTypeCache::FromDescriptor(mirror::ClassLoader* loader, const c
}
};
-const art::verifier::RegType& RegTypeCache::GetFromId(uint16_t id) const {
- DCHECK_LT(id, entries_.size());
- RegType* result = entries_[id];
- DCHECK(result != NULL);
- return *result;
-}
-
-const RegType& RegTypeCache::RegTypeFromPrimitiveType(
- Primitive::Type prim_type) const {
+const RegType& RegTypeCache::RegTypeFromPrimitiveType(Primitive::Type prim_type) const {
CHECK(RegTypeCache::primitive_initialized_);
switch (prim_type) {
case Primitive::kPrimBoolean:
@@ -113,41 +117,29 @@ const RegType& RegTypeCache::RegTypeFromPrimitiveType(
}
}
-bool RegTypeCache::MatchDescriptor(size_t idx, std::string& descriptor, bool precise) {
- RegType* cur_entry = entries_[idx];
- if (cur_entry->HasClass()) {
- // Check the descriptor in the reg_type if available.
- if(!cur_entry->descriptor_.empty()) {
- if (descriptor == cur_entry->descriptor_ && MatchingPrecisionForClass(cur_entry, precise)) {
- return true;
- }
- } else {
- // Descriptor not found in reg_type , maybe available in Class object.
- // So we might have cases where we have the class but not the descriptor
- // for that class we need the class helper to get the descriptor
- // and match it with the one we are given.
- ClassHelper kh(cur_entry->GetClass());
- if ((strcmp(descriptor.c_str(), kh.GetDescriptor()) == 0) &&
- MatchingPrecisionForClass(cur_entry, precise)) {
- return true;
- }
- }
- } else if (cur_entry->IsUnresolvedReference() && cur_entry->GetDescriptor() == descriptor) {
- return true;
+bool RegTypeCache::MatchDescriptor(size_t idx, const char* descriptor, bool precise) {
+ RegType* entry = entries_[idx];
+ if (entry->descriptor_ != descriptor) {
+ return false;
+ }
+ if (entry->HasClass()) {
+ return MatchingPrecisionForClass(entry, precise);
}
- return false;
+ // There is no notion of precise unresolved references, the precise information is just dropped
+ // on the floor.
+ DCHECK(entry->IsUnresolvedReference());
+ return true;
}
-
-mirror::Class* RegTypeCache::ResolveClass(std::string descriptor, mirror::ClassLoader* loader) {
+mirror::Class* RegTypeCache::ResolveClass(const char* descriptor, mirror::ClassLoader* loader) {
// Class was not found, must create new type.
// Try resolving class
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
mirror::Class* klass = NULL;
if (can_load_classes_) {
- klass = class_linker->FindClass(descriptor.c_str(), loader);
+ klass = class_linker->FindClass(descriptor, loader);
} else {
- klass = class_linker->LookupClass(descriptor.c_str(), loader);
+ klass = class_linker->LookupClass(descriptor, loader);
if (klass != NULL && !klass->IsLoaded()) {
// We found the class but without it being loaded its not safe for use.
klass = NULL;
@@ -155,6 +147,7 @@ mirror::Class* RegTypeCache::ResolveClass(std::string descriptor, mirror::ClassL
}
return klass;
}
+
void RegTypeCache::ClearException() {
if (can_load_classes_) {
DCHECK(Thread::Current()->IsExceptionPending());
@@ -163,8 +156,9 @@ void RegTypeCache::ClearException() {
DCHECK(!Thread::Current()->IsExceptionPending());
}
}
-const RegType& RegTypeCache::From(mirror::ClassLoader* loader, std::string descriptor, bool precise) {
+const RegType& RegTypeCache::From(mirror::ClassLoader* loader, const char* descriptor,
+ bool precise) {
// Try looking up the class in the cache first.
for (size_t i = primitive_count_; i < entries_.size(); i++) {
if (MatchDescriptor(i, descriptor, precise)) {
@@ -185,7 +179,7 @@ const RegType& RegTypeCache::From(mirror::ClassLoader* loader, std::string descr
// 2- Precise Flag passed as true.
RegType* entry;
// Create an imprecise type if we can't tell for a fact that it is precise.
- if ((klass->IsFinal()) || precise) {
+ if (klass->CannotBeAssignedFromOtherTypes() || precise) {
DCHECK(!(klass->IsAbstract()) || klass->IsArrayClass());
DCHECK(!klass->IsInterface());
entry = new PreciseReferenceType(klass, descriptor, entries_.size());
@@ -198,7 +192,7 @@ const RegType& RegTypeCache::From(mirror::ClassLoader* loader, std::string descr
// We tried loading the class and failed, this might get an exception raised
// so we want to clear it before we go on.
ClearException();
- if (IsValidDescriptor(descriptor.c_str())) {
+ if (IsValidDescriptor(descriptor)) {
RegType* entry = new UnresolvedReferenceType(descriptor, entries_.size());
entries_.push_back(entry);
return *entry;
@@ -209,25 +203,26 @@ const RegType& RegTypeCache::From(mirror::ClassLoader* loader, std::string descr
}
}
}
-const RegType& RegTypeCache::FromClass(mirror::Class* klass, bool precise) {
+
+const RegType& RegTypeCache::FromClass(const char* descriptor, mirror::Class* klass, bool precise) {
if (klass->IsPrimitive()) {
+ // Note: precise isn't used for primitive classes. A char is assignable to an int. All
+ // primitive classes are final.
return RegTypeFromPrimitiveType(klass->GetPrimitiveType());
} else {
// Look for the reference in the list of entries to have.
for (size_t i = primitive_count_; i < entries_.size(); i++) {
RegType* cur_entry = entries_[i];
- if ((cur_entry->HasClass()) && cur_entry->GetClass() == klass &&
- MatchingPrecisionForClass(cur_entry, precise)) {
+ if (cur_entry->klass_ == klass && MatchingPrecisionForClass(cur_entry, precise)) {
return *cur_entry;
}
}
// No reference to the class was found, create new reference.
RegType* entry;
- std::string empty = "";
if (precise) {
- entry = new PreciseReferenceType(klass, empty, entries_.size());
+ entry = new PreciseReferenceType(klass, descriptor, entries_.size());
} else {
- entry = new ReferenceType(klass, empty, entries_.size());
+ entry = new ReferenceType(klass, descriptor, entries_.size());
}
entries_.push_back(entry);
return *entry;
@@ -309,13 +304,14 @@ const RegType& RegTypeCache::FromUnresolvedMerge(const RegType& left, const RegT
// Create entry.
RegType* entry = new UnresolvedMergedType(left.GetId(), right.GetId(), this, entries_.size());
entries_.push_back(entry);
-#ifndef NDEBUG
- UnresolvedMergedType* tmp_entry = down_cast<UnresolvedMergedType*>(entry);
- std::set<uint16_t> check_types = tmp_entry->GetMergedTypes();
- CHECK(check_types == types);
-#endif
+ if (kIsDebugBuild) {
+ UnresolvedMergedType* tmp_entry = down_cast<UnresolvedMergedType*>(entry);
+ std::set<uint16_t> check_types = tmp_entry->GetMergedTypes();
+ CHECK(check_types == types);
+ }
return *entry;
}
+
const RegType& RegTypeCache::FromUnresolvedSuperClass(const RegType& child) {
// Check if entry already exists.
for (size_t i = primitive_count_; i < entries_.size(); i++) {
@@ -334,11 +330,12 @@ const RegType& RegTypeCache::FromUnresolvedSuperClass(const RegType& child) {
entries_.push_back(entry);
return *entry;
}
+
const RegType& RegTypeCache::Uninitialized(const RegType& type, uint32_t allocation_pc) {
RegType* entry = NULL;
RegType* cur_entry = NULL;
+ const std::string& descriptor(type.GetDescriptor());
if (type.IsUnresolvedTypes()) {
- std::string descriptor(type.GetDescriptor());
for (size_t i = primitive_count_; i < entries_.size(); i++) {
cur_entry = entries_[i];
if (cur_entry->IsUnresolvedAndUninitializedReference() &&
@@ -353,23 +350,23 @@ const RegType& RegTypeCache::Uninitialized(const RegType& type, uint32_t allocat
for (size_t i = primitive_count_; i < entries_.size(); i++) {
cur_entry = entries_[i];
if (cur_entry->IsUninitializedReference() &&
- down_cast<UninitialisedReferenceType*>(cur_entry)
+ down_cast<UninitializedReferenceType*>(cur_entry)
->GetAllocationPc() == allocation_pc &&
cur_entry->GetClass() == klass) {
return *cur_entry;
}
}
- std::string descriptor("");
- entry = new UninitialisedReferenceType(klass, descriptor, allocation_pc, entries_.size());
+ entry = new UninitializedReferenceType(klass, descriptor, allocation_pc, entries_.size());
}
entries_.push_back(entry);
return *entry;
}
+
const RegType& RegTypeCache::FromUninitialized(const RegType& uninit_type) {
RegType* entry;
if (uninit_type.IsUnresolvedTypes()) {
- std::string descriptor(uninit_type.GetDescriptor());
+ const std::string& descriptor(uninit_type.GetDescriptor());
for (size_t i = primitive_count_; i < entries_.size(); i++) {
RegType* cur_entry = entries_[i];
if (cur_entry->IsUnresolvedReference() &&
@@ -377,63 +374,52 @@ const RegType& RegTypeCache::FromUninitialized(const RegType& uninit_type) {
return *cur_entry;
}
}
- entry = new UnresolvedReferenceType(descriptor, entries_.size());
+ entry = new UnresolvedReferenceType(descriptor.c_str(), entries_.size());
} else {
mirror::Class* klass = uninit_type.GetClass();
if(uninit_type.IsUninitializedThisReference() && !klass->IsFinal()) {
- // For uninitialized this reference look for reference types that are not precise.
+ // For uninitialized "this reference" look for reference types that are not precise.
for (size_t i = primitive_count_; i < entries_.size(); i++) {
RegType* cur_entry = entries_[i];
if (cur_entry->IsReference() && cur_entry->GetClass() == klass) {
return *cur_entry;
}
}
- std::string descriptor("");
- entry = new ReferenceType(klass, descriptor, entries_.size());
- } else {
- std::string descriptor;
- if (klass->IsFinal()) {
- if (klass->IsInstantiable()) {
- for (size_t i = primitive_count_; i < entries_.size(); i++) {
- RegType* cur_entry = entries_[i];
- if (cur_entry->IsPreciseReference() && cur_entry->GetClass() == klass) {
- return *cur_entry;
- }
- }
- // Precise type was not found , create one !
- entry = new PreciseReferenceType(klass, descriptor, entries_.size());
- } else {
- return Conflict();
- }
- } else {
- // Not a final class, create an imprecise reference. Look up if we have it in the cache first.
- for (size_t i = primitive_count_; i < entries_.size(); i++) {
- RegType* cur_entry = entries_[i];
- if (cur_entry->IsReference() && !(cur_entry->IsPrecise()) &&
- cur_entry->GetClass() == klass) {
- return *cur_entry;
- }
+ entry = new ReferenceType(klass, "", entries_.size());
+ } else if (klass->IsInstantiable()) {
+ // We're uninitialized because of allocation, look or create a precise type as allocations
+ // may only create objects of that type.
+ for (size_t i = primitive_count_; i < entries_.size(); i++) {
+ RegType* cur_entry = entries_[i];
+ if (cur_entry->IsPreciseReference() && cur_entry->GetClass() == klass) {
+ return *cur_entry;
}
- entry = new ReferenceType(klass, descriptor, entries_.size());
}
+ entry = new PreciseReferenceType(klass, uninit_type.GetDescriptor(), entries_.size());
+ } else {
+ return Conflict();
}
}
entries_.push_back(entry);
return *entry;
}
-const RegType& RegTypeCache::ByteConstant() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+
+const RegType& RegTypeCache::ByteConstant() {
return FromCat1Const(std::numeric_limits<jbyte>::min(), false);
}
-const RegType& RegTypeCache::ShortConstant() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+
+const RegType& RegTypeCache::ShortConstant() {
return FromCat1Const(std::numeric_limits<jshort>::min(), false);
}
-const RegType& RegTypeCache::IntConstant() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+
+const RegType& RegTypeCache::IntConstant() {
return FromCat1Const(std::numeric_limits<jint>::max(), false);
}
+
const RegType& RegTypeCache::UninitializedThisArgument(const RegType& type) {
RegType* entry;
+ const std::string& descriptor(type.GetDescriptor());
if (type.IsUnresolvedTypes()) {
- std::string descriptor(type.GetDescriptor());
for (size_t i = primitive_count_; i < entries_.size(); i++) {
RegType* cur_entry = entries_[i];
if (cur_entry->IsUnresolvedAndUninitializedThisReference() &&
@@ -441,26 +427,26 @@ const RegType& RegTypeCache::UninitializedThisArgument(const RegType& type) {
return *cur_entry;
}
}
- entry = new UnresolvedUninitialisedThisRefType(descriptor, entries_.size());
+ entry = new UnresolvedUninitializedThisRefType(descriptor, entries_.size());
} else {
mirror::Class* klass = type.GetClass();
for (size_t i = primitive_count_; i < entries_.size(); i++) {
RegType* cur_entry = entries_[i];
- if (cur_entry->IsUninitializedThisReference() &&
- cur_entry->GetClass() == klass) {
+ if (cur_entry->IsUninitializedThisReference() && cur_entry->GetClass() == klass) {
return *cur_entry;
}
}
- std::string descriptor("");
- entry = new UninitialisedThisReferenceType(klass, descriptor, entries_.size());
+ entry = new UninitializedThisReferenceType(klass, descriptor, entries_.size());
}
entries_.push_back(entry);
return *entry;
}
+
const RegType& RegTypeCache::FromCat1Const(int32_t value, bool precise) {
for (size_t i = primitive_count_; i < entries_.size(); i++) {
RegType* cur_entry = entries_[i];
- if (cur_entry->IsConstant() && cur_entry->IsPreciseConstant() == precise &&
+ if (cur_entry->klass_ == NULL && cur_entry->IsConstant() &&
+ cur_entry->IsPreciseConstant() == precise &&
(down_cast<ConstantType*>(cur_entry))->ConstantValue() == value) {
return *cur_entry;
}
@@ -514,12 +500,13 @@ const RegType& RegTypeCache::FromCat2ConstHi(int32_t value, bool precise) {
const RegType& RegTypeCache::GetComponentType(const RegType& array, mirror::ClassLoader* loader) {
CHECK(array.IsArrayTypes());
if (array.IsUnresolvedTypes()) {
- std::string descriptor(array.GetDescriptor());
- std::string component(descriptor.substr(1, descriptor.size() - 1));
+ const std::string& descriptor(array.GetDescriptor());
+ const std::string component(descriptor.substr(1, descriptor.size() - 1));
return FromDescriptor(loader, component.c_str(), false);
} else {
mirror::Class* klass = array.GetClass()->GetComponentType();
- return FromClass(klass, klass->IsFinal());
+ return FromClass(ClassHelper(klass).GetDescriptor(), klass,
+ klass->CannotBeAssignedFromOtherTypes());
}
}
diff --git a/src/verifier/reg_type_cache.h b/src/verifier/reg_type_cache.h
index 602c95086b..d70123c2de 100644
--- a/src/verifier/reg_type_cache.h
+++ b/src/verifier/reg_type_cache.h
@@ -39,6 +39,7 @@ const size_t kNumPrimitives = 12;
class RegTypeCache {
public:
explicit RegTypeCache(bool can_load_classes) : can_load_classes_(can_load_classes) {
+ entries_.reserve(64);
FillPrimitiveTypes();
}
~RegTypeCache();
@@ -52,13 +53,13 @@ class RegTypeCache {
}
static void ShutDown();
const art::verifier::RegType& GetFromId(uint16_t id) const;
- const RegType& From(mirror::ClassLoader* loader, std::string descriptor, bool precise)
+ const RegType& From(mirror::ClassLoader* loader, const char* descriptor, bool precise)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
template <class Type>
- static Type* CreatePrimitiveTypeInstance(std::string descriptor)
+ static Type* CreatePrimitiveTypeInstance(const std::string& descriptor)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
void FillPrimitiveTypes() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- const RegType& FromClass(mirror::Class* klass, bool precise)
+ const RegType& FromClass(const char* descriptor, mirror::Class* klass, bool precise)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
const RegType& FromCat1Const(int32_t value, bool precise)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -152,10 +153,10 @@ class RegTypeCache {
// Whether or not we're allowed to load classes.
const bool can_load_classes_;
DISALLOW_COPY_AND_ASSIGN(RegTypeCache);
- mirror::Class* ResolveClass(std::string descriptor, mirror::ClassLoader* loader)
+ mirror::Class* ResolveClass(const char* descriptor, mirror::ClassLoader* loader)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
void ClearException();
- bool MatchDescriptor(size_t idx, std::string& descriptor, bool precise)
+ bool MatchDescriptor(size_t idx, const char* descriptor, bool precise)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
};
diff --git a/src/verifier/reg_type_test.cc b/src/verifier/reg_type_test.cc
index 9b46a7fbea..f37edff6ac 100644
--- a/src/verifier/reg_type_test.cc
+++ b/src/verifier/reg_type_test.cc
@@ -74,7 +74,6 @@ TEST_F(RegTypeTest, Pairs) {
}
TEST_F(RegTypeTest, Primitives) {
-
ScopedObjectAccess soa(Thread::Current());
RegTypeCache cache(true);
@@ -108,6 +107,7 @@ TEST_F(RegTypeTest, Primitives) {
EXPECT_FALSE(bool_reg_type.IsLongTypes());
EXPECT_FALSE(bool_reg_type.IsDoubleTypes());
EXPECT_TRUE(bool_reg_type.IsArrayIndexTypes());
+ EXPECT_FALSE(bool_reg_type.IsNonZeroReferenceTypes());
const RegType& byte_reg_type = cache.Byte();
EXPECT_FALSE(byte_reg_type.IsUndefined());
@@ -139,6 +139,7 @@ TEST_F(RegTypeTest, Primitives) {
EXPECT_FALSE(byte_reg_type.IsLongTypes());
EXPECT_FALSE(byte_reg_type.IsDoubleTypes());
EXPECT_TRUE(byte_reg_type.IsArrayIndexTypes());
+ EXPECT_FALSE(byte_reg_type.IsNonZeroReferenceTypes());
const RegType& char_reg_type = cache.Char();
EXPECT_FALSE(char_reg_type.IsUndefined());
@@ -170,6 +171,7 @@ TEST_F(RegTypeTest, Primitives) {
EXPECT_FALSE(char_reg_type.IsLongTypes());
EXPECT_FALSE(char_reg_type.IsDoubleTypes());
EXPECT_TRUE(char_reg_type.IsArrayIndexTypes());
+ EXPECT_FALSE(char_reg_type.IsNonZeroReferenceTypes());
const RegType& short_reg_type = cache.Short();
EXPECT_FALSE(short_reg_type.IsUndefined());
@@ -201,6 +203,7 @@ TEST_F(RegTypeTest, Primitives) {
EXPECT_FALSE(short_reg_type.IsLongTypes());
EXPECT_FALSE(short_reg_type.IsDoubleTypes());
EXPECT_TRUE(short_reg_type.IsArrayIndexTypes());
+ EXPECT_FALSE(short_reg_type.IsNonZeroReferenceTypes());
const RegType& int_reg_type = cache.Integer();
EXPECT_FALSE(int_reg_type.IsUndefined());
@@ -232,6 +235,7 @@ TEST_F(RegTypeTest, Primitives) {
EXPECT_FALSE(int_reg_type.IsLongTypes());
EXPECT_FALSE(int_reg_type.IsDoubleTypes());
EXPECT_TRUE(int_reg_type.IsArrayIndexTypes());
+ EXPECT_FALSE(int_reg_type.IsNonZeroReferenceTypes());
const RegType& long_reg_type = cache.LongLo();
EXPECT_FALSE(long_reg_type.IsUndefined());
@@ -263,6 +267,7 @@ TEST_F(RegTypeTest, Primitives) {
EXPECT_TRUE(long_reg_type.IsLongTypes());
EXPECT_FALSE(long_reg_type.IsDoubleTypes());
EXPECT_FALSE(long_reg_type.IsArrayIndexTypes());
+ EXPECT_FALSE(long_reg_type.IsNonZeroReferenceTypes());
const RegType& float_reg_type = cache.Float();
EXPECT_FALSE(float_reg_type.IsUndefined());
@@ -294,6 +299,7 @@ TEST_F(RegTypeTest, Primitives) {
EXPECT_FALSE(float_reg_type.IsLongTypes());
EXPECT_FALSE(float_reg_type.IsDoubleTypes());
EXPECT_FALSE(float_reg_type.IsArrayIndexTypes());
+ EXPECT_FALSE(float_reg_type.IsNonZeroReferenceTypes());
const RegType& double_reg_type = cache.DoubleLo();
EXPECT_FALSE(double_reg_type.IsUndefined());
@@ -325,6 +331,7 @@ TEST_F(RegTypeTest, Primitives) {
EXPECT_FALSE(double_reg_type.IsLongTypes());
EXPECT_TRUE(double_reg_type.IsDoubleTypes());
EXPECT_FALSE(double_reg_type.IsArrayIndexTypes());
+ EXPECT_FALSE(double_reg_type.IsNonZeroReferenceTypes());
}
@@ -352,12 +359,14 @@ TEST_F(RegTypeReferenceTest, UnresolvedType) {
RegTypeCache cache(true);
const RegType& ref_type_0 = cache.FromDescriptor(NULL, "Ljava/lang/DoesNotExist;", true);
EXPECT_TRUE(ref_type_0.IsUnresolvedReference());
+ EXPECT_TRUE(ref_type_0.IsNonZeroReferenceTypes());
const RegType& ref_type_1 = cache.FromDescriptor(NULL, "Ljava/lang/DoesNotExist;", true);
EXPECT_TRUE(ref_type_0.Equals(ref_type_1));
const RegType& unresolved_super_class = cache.FromUnresolvedSuperClass(ref_type_0);
EXPECT_TRUE(unresolved_super_class.IsUnresolvedSuperClass());
+ EXPECT_TRUE(unresolved_super_class.IsNonZeroReferenceTypes());
}
TEST_F(RegTypeReferenceTest, UnresolvedUnintializedType) {
@@ -372,6 +381,7 @@ TEST_F(RegTypeReferenceTest, UnresolvedUnintializedType) {
const RegType& unresolved_unintialised = cache.Uninitialized(ref_type, 1101ull);
EXPECT_TRUE(unresolved_unintialised.IsUnresolvedAndUninitializedReference());
EXPECT_TRUE(unresolved_unintialised.IsUninitializedTypes());
+ EXPECT_TRUE(unresolved_unintialised.IsNonZeroReferenceTypes());
// Create an uninitialized type of this unresolved type with different PC
const RegType& ref_type_unresolved_unintialised_1 = cache.Uninitialized(ref_type, 1102ull);
EXPECT_TRUE(unresolved_unintialised.IsUnresolvedAndUninitializedReference());
diff --git a/src/verifier/register_line-inl.h b/src/verifier/register_line-inl.h
new file mode 100644
index 0000000000..157e136cc1
--- /dev/null
+++ b/src/verifier/register_line-inl.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_SRC_VERIFIER_REGISTER_LINE_INL_H_
+#define ART_SRC_VERIFIER_REGISTER_LINE_INL_H_
+
+#include "register_line.h"
+#include "method_verifier.h"
+
+namespace art {
+namespace verifier {
+
+inline const RegType& RegisterLine::GetRegisterType(uint32_t vsrc) const {
+ // The register index was validated during the static pass, so we don't need to check it here.
+ DCHECK_LT(vsrc, num_regs_);
+ return verifier_->GetRegTypeCache()->GetFromId(line_[vsrc]);
+}
+
+} // namespace verifier
+} // namespace art
+
+#endif // ART_SRC_VERIFIER_REGISTER_LINE_INL_H_
diff --git a/src/verifier/register_line.cc b/src/verifier/register_line.cc
index 544a9ee4c0..3a2145b9bb 100644
--- a/src/verifier/register_line.cc
+++ b/src/verifier/register_line.cc
@@ -16,7 +16,9 @@
#include "register_line.h"
+#include "dex_instruction-inl.h"
#include "method_verifier.h"
+#include "register_line-inl.h"
namespace art {
namespace verifier {
@@ -92,22 +94,18 @@ void RegisterLine::SetResultRegisterTypeWide(const RegType& new_type1,
result_[1] = new_type2.GetId();
}
-const RegType& RegisterLine::GetRegisterType(uint32_t vsrc) const {
- // The register index was validated during the static pass, so we don't need to check it here.
- DCHECK_LT(vsrc, num_regs_);
- return verifier_->GetRegTypeCache()->GetFromId(line_[vsrc]);
-}
-
-const RegType& RegisterLine::GetInvocationThis(const DecodedInstruction& dec_insn) {
- if (dec_insn.vA < 1) {
+const RegType& RegisterLine::GetInvocationThis(const Instruction* inst, bool is_range) {
+ const size_t args_count = is_range ? inst->VRegA_3rc() : inst->VRegA_35c();
+ if (args_count < 1) {
verifier_->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invoke lacks 'this'";
return verifier_->GetRegTypeCache()->Conflict();
}
/* get the element type of the array held in vsrc */
- const RegType& this_type = GetRegisterType(dec_insn.vC);
+ const uint32_t this_reg = (is_range) ? inst->VRegC_3rc() : inst->VRegC_35c();
+ const RegType& this_type = GetRegisterType(this_reg);
if (!this_type.IsReferenceTypes()) {
verifier_->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "tried to get class from non-reference register v"
- << dec_insn.vC << " (type=" << this_type << ")";
+ << this_reg << " (type=" << this_type << ")";
return verifier_->GetRegTypeCache()->Conflict();
}
return this_type;
@@ -260,125 +258,135 @@ void RegisterLine::CopyResultRegister2(uint32_t vdst) {
}
}
-void RegisterLine::CheckUnaryOp(const DecodedInstruction& dec_insn,
+void RegisterLine::CheckUnaryOp(const Instruction* inst,
const RegType& dst_type,
const RegType& src_type) {
- if (VerifyRegisterType(dec_insn.vB, src_type)) {
- SetRegisterType(dec_insn.vA, dst_type);
+ if (VerifyRegisterType(inst->VRegB_12x(), src_type)) {
+ SetRegisterType(inst->VRegA_12x(), dst_type);
}
}
-void RegisterLine::CheckUnaryOpWide(const DecodedInstruction& dec_insn,
+void RegisterLine::CheckUnaryOpWide(const Instruction* inst,
const RegType& dst_type1, const RegType& dst_type2,
const RegType& src_type1, const RegType& src_type2) {
- if (VerifyRegisterTypeWide(dec_insn.vB, src_type1, src_type2)) {
- SetRegisterTypeWide(dec_insn.vA, dst_type1, dst_type2);
+ if (VerifyRegisterTypeWide(inst->VRegB_12x(), src_type1, src_type2)) {
+ SetRegisterTypeWide(inst->VRegA_12x(), dst_type1, dst_type2);
}
}
-void RegisterLine::CheckUnaryOpToWide(const DecodedInstruction& dec_insn,
+void RegisterLine::CheckUnaryOpToWide(const Instruction* inst,
const RegType& dst_type1, const RegType& dst_type2,
const RegType& src_type) {
- if (VerifyRegisterType(dec_insn.vB, src_type)) {
- SetRegisterTypeWide(dec_insn.vA, dst_type1, dst_type2);
+ if (VerifyRegisterType(inst->VRegB_12x(), src_type)) {
+ SetRegisterTypeWide(inst->VRegA_12x(), dst_type1, dst_type2);
}
}
-void RegisterLine::CheckUnaryOpFromWide(const DecodedInstruction& dec_insn,
+void RegisterLine::CheckUnaryOpFromWide(const Instruction* inst,
const RegType& dst_type,
const RegType& src_type1, const RegType& src_type2) {
- if (VerifyRegisterTypeWide(dec_insn.vB, src_type1, src_type2)) {
- SetRegisterType(dec_insn.vA, dst_type);
+ if (VerifyRegisterTypeWide(inst->VRegB_12x(), src_type1, src_type2)) {
+ SetRegisterType(inst->VRegA_12x(), dst_type);
}
}
-void RegisterLine::CheckBinaryOp(const DecodedInstruction& dec_insn,
+void RegisterLine::CheckBinaryOp(const Instruction* inst,
const RegType& dst_type,
const RegType& src_type1, const RegType& src_type2,
bool check_boolean_op) {
- if (VerifyRegisterType(dec_insn.vB, src_type1) &&
- VerifyRegisterType(dec_insn.vC, src_type2)) {
+ const uint32_t vregB = inst->VRegB_23x();
+ const uint32_t vregC = inst->VRegC_23x();
+ if (VerifyRegisterType(vregB, src_type1) &&
+ VerifyRegisterType(vregC, src_type2)) {
if (check_boolean_op) {
DCHECK(dst_type.IsInteger());
- if (GetRegisterType(dec_insn.vB).IsBooleanTypes() &&
- GetRegisterType(dec_insn.vC).IsBooleanTypes()) {
- SetRegisterType(dec_insn.vA, verifier_->GetRegTypeCache()->Boolean());
+ if (GetRegisterType(vregB).IsBooleanTypes() &&
+ GetRegisterType(vregC).IsBooleanTypes()) {
+ SetRegisterType(inst->VRegA_23x(), verifier_->GetRegTypeCache()->Boolean());
return;
}
}
- SetRegisterType(dec_insn.vA, dst_type);
+ SetRegisterType(inst->VRegA_23x(), dst_type);
}
}
-void RegisterLine::CheckBinaryOpWide(const DecodedInstruction& dec_insn,
+void RegisterLine::CheckBinaryOpWide(const Instruction* inst,
const RegType& dst_type1, const RegType& dst_type2,
const RegType& src_type1_1, const RegType& src_type1_2,
const RegType& src_type2_1, const RegType& src_type2_2) {
- if (VerifyRegisterTypeWide(dec_insn.vB, src_type1_1, src_type1_2) &&
- VerifyRegisterTypeWide(dec_insn.vC, src_type2_1, src_type2_2)) {
- SetRegisterTypeWide(dec_insn.vA, dst_type1, dst_type2);
+ if (VerifyRegisterTypeWide(inst->VRegB_23x(), src_type1_1, src_type1_2) &&
+ VerifyRegisterTypeWide(inst->VRegC_23x(), src_type2_1, src_type2_2)) {
+ SetRegisterTypeWide(inst->VRegA_23x(), dst_type1, dst_type2);
}
}
-void RegisterLine::CheckBinaryOpWideShift(const DecodedInstruction& dec_insn,
+void RegisterLine::CheckBinaryOpWideShift(const Instruction* inst,
const RegType& long_lo_type, const RegType& long_hi_type,
const RegType& int_type) {
- if (VerifyRegisterTypeWide(dec_insn.vB, long_lo_type, long_hi_type) &&
- VerifyRegisterType(dec_insn.vC, int_type)) {
- SetRegisterTypeWide(dec_insn.vA, long_lo_type, long_hi_type);
+ if (VerifyRegisterTypeWide(inst->VRegB_23x(), long_lo_type, long_hi_type) &&
+ VerifyRegisterType(inst->VRegC_23x(), int_type)) {
+ SetRegisterTypeWide(inst->VRegA_23x(), long_lo_type, long_hi_type);
}
}
-void RegisterLine::CheckBinaryOp2addr(const DecodedInstruction& dec_insn,
+void RegisterLine::CheckBinaryOp2addr(const Instruction* inst,
const RegType& dst_type, const RegType& src_type1,
const RegType& src_type2, bool check_boolean_op) {
- if (VerifyRegisterType(dec_insn.vA, src_type1) &&
- VerifyRegisterType(dec_insn.vB, src_type2)) {
+ const uint32_t vregA = inst->VRegA_12x();
+ const uint32_t vregB = inst->VRegB_12x();
+ if (VerifyRegisterType(vregA, src_type1) &&
+ VerifyRegisterType(vregB, src_type2)) {
if (check_boolean_op) {
DCHECK(dst_type.IsInteger());
- if (GetRegisterType(dec_insn.vA).IsBooleanTypes() &&
- GetRegisterType(dec_insn.vB).IsBooleanTypes()) {
- SetRegisterType(dec_insn.vA, verifier_->GetRegTypeCache()->Boolean());
+ if (GetRegisterType(vregA).IsBooleanTypes() &&
+ GetRegisterType(vregB).IsBooleanTypes()) {
+ SetRegisterType(vregA, verifier_->GetRegTypeCache()->Boolean());
return;
}
}
- SetRegisterType(dec_insn.vA, dst_type);
+ SetRegisterType(vregA, dst_type);
}
}
-void RegisterLine::CheckBinaryOp2addrWide(const DecodedInstruction& dec_insn,
+void RegisterLine::CheckBinaryOp2addrWide(const Instruction* inst,
const RegType& dst_type1, const RegType& dst_type2,
const RegType& src_type1_1, const RegType& src_type1_2,
const RegType& src_type2_1, const RegType& src_type2_2) {
- if (VerifyRegisterTypeWide(dec_insn.vA, src_type1_1, src_type1_2) &&
- VerifyRegisterTypeWide(dec_insn.vB, src_type2_1, src_type2_2)) {
- SetRegisterTypeWide(dec_insn.vA, dst_type1, dst_type2);
+ const uint32_t vregA = inst->VRegA_12x();
+ const uint32_t vregB = inst->VRegB_12x();
+ if (VerifyRegisterTypeWide(vregA, src_type1_1, src_type1_2) &&
+ VerifyRegisterTypeWide(vregB, src_type2_1, src_type2_2)) {
+ SetRegisterTypeWide(vregA, dst_type1, dst_type2);
}
}
-void RegisterLine::CheckBinaryOp2addrWideShift(const DecodedInstruction& dec_insn,
+void RegisterLine::CheckBinaryOp2addrWideShift(const Instruction* inst,
const RegType& long_lo_type, const RegType& long_hi_type,
const RegType& int_type) {
- if (VerifyRegisterTypeWide(dec_insn.vA, long_lo_type, long_hi_type) &&
- VerifyRegisterType(dec_insn.vB, int_type)) {
- SetRegisterTypeWide(dec_insn.vA, long_lo_type, long_hi_type);
+ const uint32_t vregA = inst->VRegA_12x();
+ const uint32_t vregB = inst->VRegB_12x();
+ if (VerifyRegisterTypeWide(vregA, long_lo_type, long_hi_type) &&
+ VerifyRegisterType(vregB, int_type)) {
+ SetRegisterTypeWide(vregA, long_lo_type, long_hi_type);
}
}
-void RegisterLine::CheckLiteralOp(const DecodedInstruction& dec_insn,
+void RegisterLine::CheckLiteralOp(const Instruction* inst,
const RegType& dst_type, const RegType& src_type,
- bool check_boolean_op) {
- if (VerifyRegisterType(dec_insn.vB, src_type)) {
+ bool check_boolean_op, bool is_lit16) {
+ const uint32_t vregA = is_lit16 ? inst->VRegA_22s() : inst->VRegA_22b();
+ const uint32_t vregB = is_lit16 ? inst->VRegB_22s() : inst->VRegB_22b();
+ if (VerifyRegisterType(vregB, src_type)) {
if (check_boolean_op) {
DCHECK(dst_type.IsInteger());
/* check vB with the call, then check the constant manually */
- if (GetRegisterType(dec_insn.vB).IsBooleanTypes() &&
- (dec_insn.vC == 0 || dec_insn.vC == 1)) {
- SetRegisterType(dec_insn.vA, verifier_->GetRegTypeCache()->Boolean());
+ const uint32_t val = is_lit16 ? inst->VRegC_22s() : inst->VRegC_22b();
+ if (GetRegisterType(vregB).IsBooleanTypes() && (val == 0 || val == 1)) {
+ SetRegisterType(vregA, verifier_->GetRegTypeCache()->Boolean());
return;
}
}
- SetRegisterType(dec_insn.vA, dst_type);
+ SetRegisterType(vregA, dst_type);
}
}
@@ -427,6 +435,8 @@ bool RegisterLine::VerifyMonitorStackEmpty() {
bool RegisterLine::MergeRegisters(const RegisterLine* incoming_line) {
bool changed = false;
+ CHECK(NULL != incoming_line);
+ CHECK(NULL != line_.get());
for (size_t idx = 0; idx < num_regs_; idx++) {
if (line_[idx] != incoming_line->line_[idx]) {
const RegType& incoming_reg_type = incoming_line->GetRegisterType(idx);
diff --git a/src/verifier/register_line.h b/src/verifier/register_line.h
index 5719082518..5f17049e8e 100644
--- a/src/verifier/register_line.h
+++ b/src/verifier/register_line.h
@@ -169,28 +169,28 @@ class RegisterLine {
* The argument count is in vA, and the first argument is in vC, for both "simple" and "range"
* versions. We just need to make sure vA is >= 1 and then return vC.
*/
- const RegType& GetInvocationThis(const DecodedInstruction& dec_insn)
+ const RegType& GetInvocationThis(const Instruction* inst, bool is_range)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
/*
* Verify types for a simple two-register instruction (e.g. "neg-int").
* "dst_type" is stored into vA, and "src_type" is verified against vB.
*/
- void CheckUnaryOp(const DecodedInstruction& dec_insn,
- const RegType& dst_type, const RegType& src_type)
+ void CheckUnaryOp(const Instruction* inst, const RegType& dst_type,
+ const RegType& src_type)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- void CheckUnaryOpWide(const DecodedInstruction& dec_insn,
+ void CheckUnaryOpWide(const Instruction* inst,
const RegType& dst_type1, const RegType& dst_type2,
const RegType& src_type1, const RegType& src_type2)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- void CheckUnaryOpToWide(const DecodedInstruction& dec_insn,
+ void CheckUnaryOpToWide(const Instruction* inst,
const RegType& dst_type1, const RegType& dst_type2,
const RegType& src_type)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- void CheckUnaryOpFromWide(const DecodedInstruction& dec_insn,
+ void CheckUnaryOpFromWide(const Instruction* inst,
const RegType& dst_type,
const RegType& src_type1, const RegType& src_type2)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -200,18 +200,18 @@ class RegisterLine {
* "dst_type" is stored into vA, and "src_type1"/"src_type2" are verified
* against vB/vC.
*/
- void CheckBinaryOp(const DecodedInstruction& dec_insn,
+ void CheckBinaryOp(const Instruction* inst,
const RegType& dst_type, const RegType& src_type1, const RegType& src_type2,
bool check_boolean_op)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- void CheckBinaryOpWide(const DecodedInstruction& dec_insn,
+ void CheckBinaryOpWide(const Instruction* inst,
const RegType& dst_type1, const RegType& dst_type2,
const RegType& src_type1_1, const RegType& src_type1_2,
const RegType& src_type2_1, const RegType& src_type2_2)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- void CheckBinaryOpWideShift(const DecodedInstruction& dec_insn,
+ void CheckBinaryOpWideShift(const Instruction* inst,
const RegType& long_lo_type, const RegType& long_hi_type,
const RegType& int_type)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -220,19 +220,19 @@ class RegisterLine {
* Verify types for a binary "2addr" operation. "src_type1"/"src_type2"
* are verified against vA/vB, then "dst_type" is stored into vA.
*/
- void CheckBinaryOp2addr(const DecodedInstruction& dec_insn,
+ void CheckBinaryOp2addr(const Instruction* inst,
const RegType& dst_type,
const RegType& src_type1, const RegType& src_type2,
bool check_boolean_op)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- void CheckBinaryOp2addrWide(const DecodedInstruction& dec_insn,
+ void CheckBinaryOp2addrWide(const Instruction* inst,
const RegType& dst_type1, const RegType& dst_type2,
const RegType& src_type1_1, const RegType& src_type1_2,
const RegType& src_type2_1, const RegType& src_type2_2)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- void CheckBinaryOp2addrWideShift(const DecodedInstruction& dec_insn,
+ void CheckBinaryOp2addrWideShift(const Instruction* inst,
const RegType& long_lo_type, const RegType& long_hi_type,
const RegType& int_type)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -243,8 +243,9 @@ class RegisterLine {
*
* If "check_boolean_op" is set, we use the constant value in vC.
*/
- void CheckLiteralOp(const DecodedInstruction& dec_insn,
- const RegType& dst_type, const RegType& src_type, bool check_boolean_op)
+ void CheckLiteralOp(const Instruction* inst,
+ const RegType& dst_type, const RegType& src_type,
+ bool check_boolean_op, bool is_lit16)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Verify/push monitor onto the monitor stack, locking the value in reg_idx at location insn_idx.
diff --git a/src/well_known_classes.cc b/src/well_known_classes.cc
index f836f4f9b4..4d34c7350e 100644
--- a/src/well_known_classes.cc
+++ b/src/well_known_classes.cc
@@ -77,7 +77,7 @@ jfieldID WellKnownClasses::java_lang_Thread_lock;
jfieldID WellKnownClasses::java_lang_Thread_name;
jfieldID WellKnownClasses::java_lang_Thread_priority;
jfieldID WellKnownClasses::java_lang_Thread_uncaughtHandler;
-jfieldID WellKnownClasses::java_lang_Thread_vmData;
+jfieldID WellKnownClasses::java_lang_Thread_nativePeer;
jfieldID WellKnownClasses::java_lang_ThreadGroup_mainThreadGroup;
jfieldID WellKnownClasses::java_lang_ThreadGroup_name;
jfieldID WellKnownClasses::java_lang_ThreadGroup_systemThreadGroup;
@@ -172,7 +172,7 @@ void WellKnownClasses::Init(JNIEnv* env) {
java_lang_Thread_name = CacheField(env, java_lang_Thread, false, "name", "Ljava/lang/String;");
java_lang_Thread_priority = CacheField(env, java_lang_Thread, false, "priority", "I");
java_lang_Thread_uncaughtHandler = CacheField(env, java_lang_Thread, false, "uncaughtHandler", "Ljava/lang/Thread$UncaughtExceptionHandler;");
- java_lang_Thread_vmData = CacheField(env, java_lang_Thread, false, "vmData", "I");
+ java_lang_Thread_nativePeer = CacheField(env, java_lang_Thread, false, "nativePeer", "I");
java_lang_ThreadGroup_mainThreadGroup = CacheField(env, java_lang_ThreadGroup, true, "mainThreadGroup", "Ljava/lang/ThreadGroup;");
java_lang_ThreadGroup_name = CacheField(env, java_lang_ThreadGroup, false, "name", "Ljava/lang/String;");
java_lang_ThreadGroup_systemThreadGroup = CacheField(env, java_lang_ThreadGroup, true, "systemThreadGroup", "Ljava/lang/ThreadGroup;");
diff --git a/src/well_known_classes.h b/src/well_known_classes.h
index d9acf2d636..8170520d45 100644
--- a/src/well_known_classes.h
+++ b/src/well_known_classes.h
@@ -90,7 +90,7 @@ struct WellKnownClasses {
static jfieldID java_lang_Thread_name;
static jfieldID java_lang_Thread_priority;
static jfieldID java_lang_Thread_uncaughtHandler;
- static jfieldID java_lang_Thread_vmData;
+ static jfieldID java_lang_Thread_nativePeer;
static jfieldID java_lang_ThreadGroup_mainThreadGroup;
static jfieldID java_lang_ThreadGroup_name;
static jfieldID java_lang_ThreadGroup_systemThreadGroup;