summaryrefslogtreecommitdiffstats
path: root/runtime
diff options
context:
space:
mode:
authorIan Rogers <irogers@google.com>2013-10-04 11:17:26 -0700
committerIan Rogers <irogers@google.com>2013-10-08 15:54:54 -0700
commita9a8254c920ce8e22210abfc16c9842ce0aea28f (patch)
tree56614ee997940e8e3b88fef43b890e8a33e78112 /runtime
parent34633b22f74393344987a50b8aaee548a9dadc18 (diff)
downloadart-a9a8254c920ce8e22210abfc16c9842ce0aea28f.zip
art-a9a8254c920ce8e22210abfc16c9842ce0aea28f.tar.gz
art-a9a8254c920ce8e22210abfc16c9842ce0aea28f.tar.bz2
Improve quick codegen for aput-object.
1) don't type check known null. 2) if we know types in verify don't check at runtime. 3) if we're runtime checking then move all the code out-of-line. Also, don't set up a callee-save frame for check-cast, do an instance-of test then throw an exception if that fails. Tidy quick entry point of Ldivmod to Lmod which it is on x86 and mips. Fix monitor-enter/exit NPE for MIPS. Fix benign bug in mirror::Class::CannotBeAssignedFromOtherTypes, a byte[] cannot be assigned to from other types. Change-Id: I9cb3859ec70cca71ed79331ec8df5bec969d6745
Diffstat (limited to 'runtime')
-rw-r--r--runtime/arch/arm/asm_support_arm.h2
-rw-r--r--runtime/arch/arm/entrypoints_init_arm.cc14
-rw-r--r--runtime/arch/arm/quick_entrypoints_arm.S107
-rw-r--r--runtime/arch/arm/thread_arm.cc1
-rw-r--r--runtime/arch/mips/asm_support_mips.h2
-rw-r--r--runtime/arch/mips/entrypoints_init_mips.cc24
-rw-r--r--runtime/arch/mips/quick_entrypoints_mips.S125
-rw-r--r--runtime/arch/mips/thread_mips.cc1
-rw-r--r--runtime/arch/x86/asm_support_x86.h2
-rw-r--r--runtime/arch/x86/entrypoints_init_x86.cc16
-rw-r--r--runtime/arch/x86/quick_entrypoints_x86.S130
-rw-r--r--runtime/arch/x86/thread_x86.cc1
-rw-r--r--runtime/asm_support.h8
-rw-r--r--runtime/entrypoints/quick/quick_cast_entrypoints.cc37
-rw-r--r--runtime/entrypoints/quick/quick_entrypoints.h8
-rw-r--r--runtime/entrypoints/quick/quick_math_entrypoints.cc6
-rw-r--r--runtime/entrypoints/quick/quick_throw_entrypoints.cc20
-rw-r--r--runtime/mirror/class.h10
-rw-r--r--runtime/mirror/object_test.cc18
-rw-r--r--runtime/thread.cc6
-rw-r--r--runtime/verifier/method_verifier.cc66
-rw-r--r--runtime/verifier/method_verifier.h6
-rw-r--r--runtime/verifier/reg_type_cache.cc5
23 files changed, 461 insertions, 154 deletions
diff --git a/runtime/arch/arm/asm_support_arm.h b/runtime/arch/arm/asm_support_arm.h
index 69fb9c3..cfffbea 100644
--- a/runtime/arch/arm/asm_support_arm.h
+++ b/runtime/arch/arm/asm_support_arm.h
@@ -25,6 +25,8 @@
#define rSELF r9
// Offset of field Thread::suspend_count_ verified in InitCpu
#define THREAD_FLAGS_OFFSET 0
+// Offset of field Thread::card_table_ verified in InitCpu
+#define THREAD_CARD_TABLE_OFFSET 8
// Offset of field Thread::exception_ verified in InitCpu
#define THREAD_EXCEPTION_OFFSET 12
// Offset of field Thread::thin_lock_thread_id_ verified in InitCpu
diff --git a/runtime/arch/arm/entrypoints_init_arm.cc b/runtime/arch/arm/entrypoints_init_arm.cc
index e6e13be..352982f 100644
--- a/runtime/arch/arm/entrypoints_init_arm.cc
+++ b/runtime/arch/arm/entrypoints_init_arm.cc
@@ -52,7 +52,6 @@ extern "C" void* art_quick_check_and_alloc_array_with_access_check_instrumented(
// Cast entrypoints.
extern "C" uint32_t artIsAssignableFromCode(const mirror::Class* klass,
const mirror::Class* ref_class);
-extern "C" void art_quick_can_put_array_element(void*, void*);
extern "C" void art_quick_check_cast(void*, void*);
// DexCache entrypoints.
@@ -78,7 +77,10 @@ extern "C" int64_t art_quick_get64_static(uint32_t);
extern "C" void* art_quick_get_obj_instance(uint32_t, void*);
extern "C" void* art_quick_get_obj_static(uint32_t);
-// FillArray entrypoint.
+// Array entrypoints.
+extern "C" void art_quick_aput_obj_with_null_and_bound_check(void*, uint32_t, void*);
+extern "C" void art_quick_aput_obj_with_bound_check(void*, uint32_t, void*);
+extern "C" void art_quick_aput_obj(void*, uint32_t, void*);
extern "C" void art_quick_handle_fill_data(void*, void*);
// Lock entrypoints.
@@ -182,7 +184,6 @@ void InitEntryPoints(InterpreterEntryPoints* ipoints, JniEntryPoints* jpoints,
// Cast
qpoints->pInstanceofNonTrivial = artIsAssignableFromCode;
- qpoints->pCanPutArrayElement = art_quick_can_put_array_element;
qpoints->pCheckCast = art_quick_check_cast;
// DexCache
@@ -205,7 +206,10 @@ void InitEntryPoints(InterpreterEntryPoints* ipoints, JniEntryPoints* jpoints,
qpoints->pGet64Static = art_quick_get64_static;
qpoints->pGetObjStatic = art_quick_get_obj_static;
- // FillArray
+ // Array
+ qpoints->pAputObjectWithNullAndBoundCheck = art_quick_aput_obj_with_null_and_bound_check;
+ qpoints->pAputObjectWithBoundCheck = art_quick_aput_obj_with_bound_check;
+ qpoints->pAputObject = art_quick_aput_obj;
qpoints->pHandleFillArrayData = art_quick_handle_fill_data;
// JNI
@@ -236,7 +240,7 @@ void InitEntryPoints(InterpreterEntryPoints* ipoints, JniEntryPoints* jpoints,
qpoints->pD2l = art_d2l;
qpoints->pF2l = art_f2l;
qpoints->pLdiv = __aeabi_ldivmod;
- qpoints->pLdivmod = __aeabi_ldivmod; // result returned in r2:r3
+ qpoints->pLmod = __aeabi_ldivmod; // result returned in r2:r3
qpoints->pLmul = art_quick_mul_long;
qpoints->pShlLong = art_quick_shl_long;
qpoints->pShrLong = art_quick_shr_long;
diff --git a/runtime/arch/arm/quick_entrypoints_arm.S b/runtime/arch/arm/quick_entrypoints_arm.S
index cb61698..d073177 100644
--- a/runtime/arch/arm/quick_entrypoints_arm.S
+++ b/runtime/arch/arm/quick_entrypoints_arm.S
@@ -152,6 +152,7 @@ ENTRY \c_name
mov r1, r9 @ pass Thread::Current
mov r2, sp @ pass SP
b \cxx_name @ \cxx_name(Thread*, SP)
+ bkpt
END \c_name
.endm
@@ -162,6 +163,7 @@ ENTRY \c_name
mov r2, r9 @ pass Thread::Current
mov r3, sp @ pass SP
b \cxx_name @ \cxx_name(Thread*, SP)
+ bkpt
END \c_name
.endm
@@ -389,33 +391,96 @@ slow_unlock:
END art_quick_unlock_object
/*
- * Entry from managed code that calls artCheckCastFromCode and delivers exception on failure.
+ * Entry from managed code that calls artIsAssignableFromCode and on failure calls
+ * artThrowClassCastException.
*/
- .extern artCheckCastFromCode
+ .extern artThrowClassCastException
ENTRY art_quick_check_cast
- SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case exception allocation triggers GC
- mov r2, r9 @ pass Thread::Current
- mov r3, sp @ pass SP
- bl artCheckCastFromCode @ (Class* a, Class* b, Thread*, SP)
- RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
- RETURN_IF_RESULT_IS_ZERO
- DELIVER_PENDING_EXCEPTION
+ push {r0-r1, lr} @ save arguments, link register and pad
+ .save {r0-r1, lr}
+ .cfi_adjust_cfa_offset 12
+ .cfi_rel_offset r0, 0
+ .cfi_rel_offset r1, 4
+ .cfi_rel_offset lr, 8
+ sub sp, #4
+ .pad #4
+ .cfi_adjust_cfa_offset 4
+ bl artIsAssignableFromCode
+ cbz r0, throw_class_cast_exception
+ add sp, #4
+ .cfi_adjust_cfa_offset -4
+ pop {r0-r1, pc}
+throw_class_cast_exception:
+ add sp, #4
+ .cfi_adjust_cfa_offset -4
+ pop {r0-r1, lr}
+ SETUP_SAVE_ALL_CALLEE_SAVE_FRAME // save all registers as basis for long jump context
+ mov r2, r9 @ pass Thread::Current
+ mov r3, sp @ pass SP
+ b artThrowClassCastException @ (Class*, Class*, Thread*, SP)
+ bkpt
END art_quick_check_cast
/*
- * Entry from managed code that calls artCanPutArrayElementFromCode and delivers exception on
- * failure.
+ * Entry from managed code for array put operations of objects where the value being stored
+ * needs to be checked for compatibility.
+ * r0 = array, r1 = index, r2 = value
*/
- .extern artCanPutArrayElementFromCode
-ENTRY art_quick_can_put_array_element
- SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case exception allocation triggers GC
- mov r2, r9 @ pass Thread::Current
- mov r3, sp @ pass SP
- bl artCanPutArrayElementFromCode @ (Object* element, Class* array_class, Thread*, SP)
- RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
- RETURN_IF_RESULT_IS_ZERO
- DELIVER_PENDING_EXCEPTION
-END art_quick_can_put_array_element
+ENTRY art_quick_aput_obj_with_null_and_bound_check
+ tst r0, r0
+ bne art_quick_aput_obj_with_bound_check
+ b art_quick_throw_null_pointer_exception
+END art_quick_aput_obj_with_null_and_bound_check
+
+ENTRY art_quick_aput_obj_with_bound_check
+ ldr r3, [r0, #ARRAY_LENGTH_OFFSET]
+ cmp r3, r1
+ bhi art_quick_aput_obj
+ mov r0, r1
+ mov r1, r3
+ b art_quick_throw_array_bounds
+END art_quick_aput_obj_with_bound_check
+
+ENTRY art_quick_aput_obj
+ cbz r2, do_aput_null
+ ldr r3, [r0, #CLASS_OFFSET]
+ ldr ip, [r2, #CLASS_OFFSET]
+ ldr r3, [r3, #CLASS_COMPONENT_TYPE_OFFSET]
+ cmp r3, ip @ value's type == array's component type - trivial assignability
+ bne check_assignability
+do_aput:
+ add r3, r0, #OBJECT_ARRAY_DATA_OFFSET
+ str r2, [r3, r1, lsl #2]
+ ldr r3, [r9, #THREAD_CARD_TABLE_OFFSET]
+ lsr r0, r0, #7
+ strb r3, [r3, r0]
+ blx lr
+do_aput_null:
+ add r3, r0, #OBJECT_ARRAY_DATA_OFFSET
+ str r2, [r3, r1, lsl #2]
+ blx lr
+check_assignability:
+ push {r0-r2, lr} @ save arguments
+ mov r1, ip
+ mov r0, r3
+ bl artIsAssignableFromCode
+ cbz r0, throw_array_store_exception
+ pop {r0-r2, lr}
+ add r3, r0, #OBJECT_ARRAY_DATA_OFFSET
+ str r2, [r3, r1, lsl #2]
+ ldr r3, [r9, #THREAD_CARD_TABLE_OFFSET]
+ lsr r0, r0, #7
+ strb r3, [r3, r0]
+ blx lr
+throw_array_store_exception:
+ pop {r0-r2, lr}
+ SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
+ mov r1, r2
+ mov r2, r9 @ pass Thread::Current
+ mov r3, sp @ pass SP
+ b artThrowArrayStoreException @ (Class*, Class*, Thread*, SP)
+ bkpt @ unreached
+END art_quick_aput_obj
/*
* Entry from managed code when uninitialized static storage, this stub will run the class
diff --git a/runtime/arch/arm/thread_arm.cc b/runtime/arch/arm/thread_arm.cc
index 75eef60..8c1efeb 100644
--- a/runtime/arch/arm/thread_arm.cc
+++ b/runtime/arch/arm/thread_arm.cc
@@ -23,6 +23,7 @@ namespace art {
void Thread::InitCpu() {
CHECK_EQ(THREAD_FLAGS_OFFSET, OFFSETOF_MEMBER(Thread, state_and_flags_));
+ CHECK_EQ(THREAD_CARD_TABLE_OFFSET, OFFSETOF_MEMBER(Thread, card_table_));
CHECK_EQ(THREAD_EXCEPTION_OFFSET, OFFSETOF_MEMBER(Thread, exception_));
CHECK_EQ(THREAD_ID_OFFSET, OFFSETOF_MEMBER(Thread, thin_lock_thread_id_));
}
diff --git a/runtime/arch/mips/asm_support_mips.h b/runtime/arch/mips/asm_support_mips.h
index 9a66352..5307997 100644
--- a/runtime/arch/mips/asm_support_mips.h
+++ b/runtime/arch/mips/asm_support_mips.h
@@ -25,6 +25,8 @@
#define rSELF $s1
// Offset of field Thread::suspend_count_ verified in InitCpu
#define THREAD_FLAGS_OFFSET 0
+// Offset of field Thread::card_table_ verified in InitCpu
+#define THREAD_CARD_TABLE_OFFSET 8
// Offset of field Thread::exception_ verified in InitCpu
#define THREAD_EXCEPTION_OFFSET 12
diff --git a/runtime/arch/mips/entrypoints_init_mips.cc b/runtime/arch/mips/entrypoints_init_mips.cc
index 3d08298..cc975d75 100644
--- a/runtime/arch/mips/entrypoints_init_mips.cc
+++ b/runtime/arch/mips/entrypoints_init_mips.cc
@@ -51,7 +51,6 @@ extern "C" void* art_quick_check_and_alloc_array_with_access_check_instrumented(
// Cast entrypoints.
extern "C" uint32_t artIsAssignableFromCode(const mirror::Class* klass,
const mirror::Class* ref_class);
-extern "C" void art_quick_can_put_array_element(void*, void*);
extern "C" void art_quick_check_cast(void*, void*);
// DexCache entrypoints.
@@ -77,7 +76,10 @@ extern "C" int64_t art_quick_get64_static(uint32_t);
extern "C" void* art_quick_get_obj_instance(uint32_t, void*);
extern "C" void* art_quick_get_obj_static(uint32_t);
-// FillArray entrypoint.
+// Array entrypoints.
+extern "C" void art_quick_aput_obj_with_null_and_bound_check(void*, uint32_t, void*);
+extern "C" void art_quick_aput_obj_with_bound_check(void*, uint32_t, void*);
+extern "C" void art_quick_aput_obj(void*, uint32_t, void*);
extern "C" void art_quick_handle_fill_data(void*, void*);
// Lock entrypoints.
@@ -89,9 +91,9 @@ extern int32_t CmpgDouble(double a, double b);
extern int32_t CmplDouble(double a, double b);
extern int32_t CmpgFloat(float a, float b);
extern int32_t CmplFloat(float a, float b);
-extern "C" int64_t artLmulFromCode(int64_t a, int64_t b);
-extern "C" int64_t artLdivFromCode(int64_t a, int64_t b);
-extern "C" int64_t artLdivmodFromCode(int64_t a, int64_t b);
+extern "C" int64_t artLmul(int64_t a, int64_t b);
+extern "C" int64_t artLdiv(int64_t a, int64_t b);
+extern "C" int64_t artLmod(int64_t a, int64_t b);
// Math conversions.
extern "C" int32_t __fixsfsi(float op1); // FLOAT_TO_INT
@@ -183,7 +185,6 @@ void InitEntryPoints(InterpreterEntryPoints* ipoints, JniEntryPoints* jpoints,
// Cast
qpoints->pInstanceofNonTrivial = artIsAssignableFromCode;
- qpoints->pCanPutArrayElement = art_quick_can_put_array_element;
qpoints->pCheckCast = art_quick_check_cast;
// DexCache
@@ -206,7 +207,10 @@ void InitEntryPoints(InterpreterEntryPoints* ipoints, JniEntryPoints* jpoints,
qpoints->pGet64Static = art_quick_get64_static;
qpoints->pGetObjStatic = art_quick_get_obj_static;
- // FillArray
+ // Array
+ qpoints->pAputObjectWithNullAndBoundCheck = art_quick_aput_obj_with_null_and_bound_check;
+ qpoints->pAputObjectWithBoundCheck = art_quick_aput_obj_with_bound_check;
+ qpoints->pAputObject = art_quick_aput_obj;
qpoints->pHandleFillArrayData = art_quick_handle_fill_data;
// JNI
@@ -235,9 +239,9 @@ void InitEntryPoints(InterpreterEntryPoints* ipoints, JniEntryPoints* jpoints,
qpoints->pIdivmod = NULL;
qpoints->pD2l = art_d2l;
qpoints->pF2l = art_f2l;
- qpoints->pLdiv = artLdivFromCode;
- qpoints->pLdivmod = artLdivmodFromCode;
- qpoints->pLmul = artLmulFromCode;
+ qpoints->pLdiv = artLdiv;
+ qpoints->pLmod = artLmod;
+ qpoints->pLmul = artLmul;
qpoints->pShlLong = art_quick_shl_long;
qpoints->pShrLong = art_quick_shr_long;
qpoints->pUshrLong = art_quick_ushr_long;
diff --git a/runtime/arch/mips/quick_entrypoints_mips.S b/runtime/arch/mips/quick_entrypoints_mips.S
index f9b703f..e9c6698 100644
--- a/runtime/arch/mips/quick_entrypoints_mips.S
+++ b/runtime/arch/mips/quick_entrypoints_mips.S
@@ -283,6 +283,7 @@ END art_quick_deliver_exception
.extern artThrowNullPointerExceptionFromCode
ENTRY art_quick_throw_null_pointer_exception
GENERATE_GLOBAL_POINTER
+art_quick_throw_null_pointer_exception_gp_set:
SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
move $a0, rSELF # pass Thread::Current
la $t9, artThrowNullPointerExceptionFromCode
@@ -309,6 +310,7 @@ END art_quick_throw_div_zero
.extern artThrowArrayBoundsFromCode
ENTRY art_quick_throw_array_bounds
GENERATE_GLOBAL_POINTER
+art_quick_throw_array_bounds_gp_set:
SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
move $a2, rSELF # pass Thread::Current
la $t9, artThrowArrayBoundsFromCode
@@ -481,6 +483,8 @@ END art_quick_handle_fill_data
.extern artLockObjectFromCode
ENTRY art_quick_lock_object
GENERATE_GLOBAL_POINTER
+ beqz $a0, art_quick_throw_null_pointer_exception_gp_set
+ nop
SETUP_REF_ONLY_CALLEE_SAVE_FRAME # save callee saves in case we block
move $a1, rSELF # pass Thread::Current
jal artLockObjectFromCode # (Object* obj, Thread*, $sp)
@@ -494,6 +498,8 @@ END art_quick_lock_object
.extern artUnlockObjectFromCode
ENTRY art_quick_unlock_object
GENERATE_GLOBAL_POINTER
+ beqz $a0, art_quick_throw_null_pointer_exception_gp_set
+ nop
SETUP_REF_ONLY_CALLEE_SAVE_FRAME # save callee saves in case exception allocation triggers GC
move $a1, rSELF # pass Thread::Current
jal artUnlockObjectFromCode # (Object* obj, Thread*, $sp)
@@ -504,29 +510,116 @@ END art_quick_unlock_object
/*
* Entry from managed code that calls artCheckCastFromCode and delivers exception on failure.
*/
- .extern artCheckCastFromCode
+ .extern artThrowClassCastException
ENTRY art_quick_check_cast
GENERATE_GLOBAL_POINTER
- SETUP_REF_ONLY_CALLEE_SAVE_FRAME # save callee saves in case exception allocation triggers GC
- move $a2, rSELF # pass Thread::Current
- jal artCheckCastFromCode # (Class* a, Class* b, Thread*, $sp)
- move $a3, $sp # pass $sp
- RETURN_IF_ZERO
+ addiu $sp, $sp, -16
+ .cfi_adjust_cfa_offset 16
+ sw $ra, 12($sp)
+ .cfi_rel_offset 31, 12
+ sw $t9, 8($sp)
+ sw $a1, 4($sp)
+ sw $a0, 0($sp)
+ jal artIsAssignableFromCode
+ nop
+ beqz $v0, throw_class_cast_exception
+ lw $ra, 12($sp)
+ jr $ra
+ addiu $sp, $sp, 16
+ .cfi_adjust_cfa_offset -16
+throw_class_cast_exception:
+ lw $t9, 8($sp)
+ lw $a1, 4($sp)
+ lw $a0, 0($sp)
+ addiu $sp, $sp, 16
+ .cfi_adjust_cfa_offset -16
+ SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
+ move $a2, rSELF # pass Thread::Current
+ la $t9, artThrowClassCastException
+ jr $t9 # artThrowClassCastException (Class*, Class*, Thread*, SP)
+ move $a3, $sp # pass $sp
END art_quick_check_cast
/*
- * Entry from managed code that calls artCanPutArrayElementFromCode and delivers exception on
- * failure.
+ * Entry from managed code for array put operations of objects where the value being stored
+ * needs to be checked for compatibility.
+ * a0 = array, a1 = index, a2 = value
*/
- .extern artCanPutArrayElementFromCode
-ENTRY art_quick_can_put_array_element
+ENTRY art_quick_aput_obj_with_null_and_bound_check
GENERATE_GLOBAL_POINTER
- SETUP_REF_ONLY_CALLEE_SAVE_FRAME # save callee saves in case exception allocation triggers GC
- move $a2, rSELF # pass Thread::Current
- jal artCanPutArrayElementFromCode # (Object* element, Class* array_class, Thread*, $sp)
- move $a3, $sp # pass $sp
- RETURN_IF_ZERO
-END art_quick_can_put_array_element
+ bnez $a0, art_quick_aput_obj_with_bound_check_gp_set
+ nop
+ b art_quick_throw_null_pointer_exception_gp_set
+ nop
+END art_quick_aput_obj_with_null_and_bound_check
+
+ENTRY art_quick_aput_obj_with_bound_check
+ GENERATE_GLOBAL_POINTER
+art_quick_aput_obj_with_bound_check_gp_set:
+ lw $t0, ARRAY_LENGTH_OFFSET($a0)
+ sltu $t1, $a1, $t0
+ bnez $t1, art_quick_aput_obj_gp_set
+ nop
+ move $a0, $a1
+ b art_quick_throw_array_bounds_gp_set
+ move $a1, $t0
+END art_quick_aput_obj_with_bound_check
+
+ENTRY art_quick_aput_obj
+ GENERATE_GLOBAL_POINTER
+art_quick_aput_obj_gp_set:
+ beqz $a2, do_aput_null
+ nop
+ lw $t0, CLASS_OFFSET($a0)
+ lw $t1, CLASS_OFFSET($a2)
+ lw $t0, CLASS_COMPONENT_TYPE_OFFSET($t0)
+ bne $t1, $t0, check_assignability # value's type == array's component type - trivial assignability
+ nop
+do_aput:
+ sll $a1, $a1, 2
+ add $t0, $a0, $a1
+ sw $a2, OBJECT_ARRAY_DATA_OFFSET($t0)
+ lw $t0, THREAD_CARD_TABLE_OFFSET(rSELF)
+ srl $t1, $a0, 7
+ add $t1, $t1, $t0
+ sb $t0, ($t1)
+ jr $ra
+ nop
+do_aput_null:
+ sll $a1, $a1, 2
+ add $t0, $a0, $a1
+ sw $a2, OBJECT_ARRAY_DATA_OFFSET($t0)
+ jr $ra
+ nop
+check_assignability:
+ addiu $sp, $sp, -32
+ .cfi_adjust_cfa_offset 32
+ sw $ra, 28($sp)
+ .cfi_rel_offset 31, 28
+ sw $t9, 12($sp)
+ sw $a2, 8($sp)
+ sw $a1, 4($sp)
+ sw $a0, 0($sp)
+ move $a1, $t1
+ move $a0, $t0
+ jal artIsAssignableFromCode # (Class*, Class*)
+ nop
+ lw $ra, 28($sp)
+ lw $t9, 12($sp)
+ lw $a2, 8($sp)
+ lw $a1, 4($sp)
+ lw $a0, 0($sp)
+ add $sp, 32
+ .cfi_adjust_cfa_offset -32
+ bnez $v0, do_aput
+ nop
+ SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
+ move $a1, $a2
+ move $a2, rSELF # pass Thread::Current
+ la $t9, artThrowArrayStoreException
+ jr $t9 # artThrowArrayStoreException(Class*, Class*, Thread*, SP)
+ move $a3, $sp # pass $sp
+END art_quick_aput_obj
/*
* Entry from managed code when uninitialized static storage, this stub will run the class
diff --git a/runtime/arch/mips/thread_mips.cc b/runtime/arch/mips/thread_mips.cc
index 7364de0..bd54549 100644
--- a/runtime/arch/mips/thread_mips.cc
+++ b/runtime/arch/mips/thread_mips.cc
@@ -23,6 +23,7 @@ namespace art {
void Thread::InitCpu() {
CHECK_EQ(THREAD_FLAGS_OFFSET, OFFSETOF_MEMBER(Thread, state_and_flags_));
+ CHECK_EQ(THREAD_CARD_TABLE_OFFSET, OFFSETOF_MEMBER(Thread, card_table_));
CHECK_EQ(THREAD_EXCEPTION_OFFSET, OFFSETOF_MEMBER(Thread, exception_));
}
diff --git a/runtime/arch/x86/asm_support_x86.h b/runtime/arch/x86/asm_support_x86.h
index d4e0927..e817ff7 100644
--- a/runtime/arch/x86/asm_support_x86.h
+++ b/runtime/arch/x86/asm_support_x86.h
@@ -21,6 +21,8 @@
// Offset of field Thread::self_ verified in InitCpu
#define THREAD_SELF_OFFSET 40
+// Offset of field Thread::card_table_ verified in InitCpu
+#define THREAD_CARD_TABLE_OFFSET 8
// Offset of field Thread::exception_ verified in InitCpu
#define THREAD_EXCEPTION_OFFSET 12
// Offset of field Thread::thin_lock_thread_id_ verified in InitCpu
diff --git a/runtime/arch/x86/entrypoints_init_x86.cc b/runtime/arch/x86/entrypoints_init_x86.cc
index 4c87e07..89dd1b8 100644
--- a/runtime/arch/x86/entrypoints_init_x86.cc
+++ b/runtime/arch/x86/entrypoints_init_x86.cc
@@ -50,7 +50,6 @@ extern "C" void* art_quick_check_and_alloc_array_with_access_check_instrumented(
// Cast entrypoints.
extern "C" uint32_t art_quick_is_assignable(const mirror::Class* klass,
const mirror::Class* ref_class);
-extern "C" void art_quick_can_put_array_element(void*, void*);
extern "C" void art_quick_check_cast(void*, void*);
// DexCache entrypoints.
@@ -73,7 +72,10 @@ extern "C" int64_t art_quick_get64_static(uint32_t);
extern "C" void* art_quick_get_obj_instance(uint32_t, void*);
extern "C" void* art_quick_get_obj_static(uint32_t);
-// FillArray entrypoint.
+// Array entrypoints.
+extern "C" void art_quick_aput_obj_with_null_and_bound_check(void*, uint32_t, void*);
+extern "C" void art_quick_aput_obj_with_bound_check(void*, uint32_t, void*);
+extern "C" void art_quick_aput_obj(void*, uint32_t, void*);
extern "C" void art_quick_handle_fill_data(void*, void*);
// Lock entrypoints.
@@ -89,7 +91,7 @@ extern "C" int64_t art_quick_d2l(double);
extern "C" int64_t art_quick_f2l(float);
extern "C" int32_t art_quick_idivmod(int32_t, int32_t);
extern "C" int64_t art_quick_ldiv(int64_t, int64_t);
-extern "C" int64_t art_quick_ldivmod(int64_t, int64_t);
+extern "C" int64_t art_quick_lmod(int64_t, int64_t);
extern "C" int64_t art_quick_lmul(int64_t, int64_t);
extern "C" uint64_t art_quick_lshl(uint64_t, uint32_t);
extern "C" uint64_t art_quick_lshr(uint64_t, uint32_t);
@@ -165,7 +167,6 @@ void InitEntryPoints(InterpreterEntryPoints* ipoints, JniEntryPoints* jpoints,
// Cast
qpoints->pInstanceofNonTrivial = art_quick_is_assignable;
- qpoints->pCanPutArrayElement = art_quick_can_put_array_element;
qpoints->pCheckCast = art_quick_check_cast;
// DexCache
@@ -188,7 +189,10 @@ void InitEntryPoints(InterpreterEntryPoints* ipoints, JniEntryPoints* jpoints,
qpoints->pGet64Static = art_quick_get64_static;
qpoints->pGetObjStatic = art_quick_get_obj_static;
- // FillArray
+ // Array
+ qpoints->pAputObjectWithNullAndBoundCheck = art_quick_aput_obj_with_null_and_bound_check;
+ qpoints->pAputObjectWithBoundCheck = art_quick_aput_obj_with_bound_check;
+ qpoints->pAputObject = art_quick_aput_obj;
qpoints->pHandleFillArrayData = art_quick_handle_fill_data;
// JNI
@@ -218,7 +222,7 @@ void InitEntryPoints(InterpreterEntryPoints* ipoints, JniEntryPoints* jpoints,
qpoints->pD2l = art_quick_d2l;
qpoints->pF2l = art_quick_f2l;
qpoints->pLdiv = art_quick_ldiv;
- qpoints->pLdivmod = art_quick_ldivmod;
+ qpoints->pLmod = art_quick_lmod;
qpoints->pLmul = art_quick_lmul;
qpoints->pShlLong = art_quick_lshl;
qpoints->pShrLong = art_quick_lshr;
diff --git a/runtime/arch/x86/quick_entrypoints_x86.S b/runtime/arch/x86/quick_entrypoints_x86.S
index 6be73d1..9fce72f 100644
--- a/runtime/arch/x86/quick_entrypoints_x86.S
+++ b/runtime/arch/x86/quick_entrypoints_x86.S
@@ -479,14 +479,115 @@ END_FUNCTION art_quick_unlock_object
DEFINE_FUNCTION art_quick_is_assignable
PUSH eax // alignment padding
- PUSH ecx // pass arg2
- PUSH eax // pass arg1
- call SYMBOL(artIsAssignableFromCode) // (Class* a, Class* b, Thread*, SP)
+ PUSH ecx // pass arg2 - obj->klass
+ PUSH eax // pass arg1 - checked class
+ call SYMBOL(artIsAssignableFromCode) // (Class* klass, Class* ref_klass)
addl LITERAL(12), %esp // pop arguments
.cfi_adjust_cfa_offset -12
ret
END_FUNCTION art_quick_is_assignable
+DEFINE_FUNCTION art_quick_check_cast
+ PUSH eax // alignment padding
+ PUSH ecx // pass arg2 - obj->klass
+ PUSH eax // pass arg1 - checked class
+ call SYMBOL(artIsAssignableFromCode) // (Class* klass, Class* ref_klass)
+ testl %eax, %eax
+ jz 1f // jump forward if not assignable
+ addl LITERAL(12), %esp // pop arguments
+ .cfi_adjust_cfa_offset -12
+ ret
+1:
+ POP eax // pop arguments
+ POP ecx
+ addl LITERAL(4), %esp
+ .cfi_adjust_cfa_offset -12
+ SETUP_SAVE_ALL_CALLEE_SAVE_FRAME // save all registers as basis for long jump context
+ mov %esp, %edx
+ // Outgoing argument set up
+ PUSH edx // pass SP
+ pushl %fs:THREAD_SELF_OFFSET // pass Thread::Current()
+ .cfi_adjust_cfa_offset 4
+ PUSH ecx // pass arg2
+ PUSH eax // pass arg1
+ call SYMBOL(artThrowClassCastException) // (Class* a, Class* b, Thread*, SP)
+ int3 // unreached
+END_FUNCTION art_quick_check_cast
+
+ /*
+ * Entry from managed code for array put operations of objects where the value being stored
+ * needs to be checked for compatibility.
+ * eax = array, ecx = index, edx = value
+ */
+DEFINE_FUNCTION art_quick_aput_obj_with_null_and_bound_check
+ testl %eax, %eax
+ jnz art_quick_aput_obj_with_bound_check
+ jmp art_quick_throw_null_pointer_exception
+END_FUNCTION art_quick_aput_obj_with_null_and_bound_check
+
+DEFINE_FUNCTION art_quick_aput_obj_with_bound_check
+ movl ARRAY_LENGTH_OFFSET(%eax), %ebx
+ cmpl %ebx, %ecx
+ jb art_quick_aput_obj
+ mov %ecx, %eax
+ mov %ebx, %ecx
+ jmp art_quick_throw_array_bounds
+END_FUNCTION art_quick_aput_obj_with_bound_check
+
+DEFINE_FUNCTION art_quick_aput_obj
+ test %edx, %edx // store of null
+ jz do_aput_null
+ movl CLASS_OFFSET(%eax), %ebx
+ movl CLASS_COMPONENT_TYPE_OFFSET(%ebx), %ebx
+ cmpl CLASS_OFFSET(%edx), %ebx // value's type == array's component type - trivial assignability
+ jne check_assignability
+do_aput:
+ movl %edx, OBJECT_ARRAY_DATA_OFFSET(%eax, %ecx, 4)
+ movl %fs:THREAD_CARD_TABLE_OFFSET, %edx
+ shrl LITERAL(7), %eax
+ movb %dl, (%edx, %eax)
+ ret
+do_aput_null:
+ movl %edx, OBJECT_ARRAY_DATA_OFFSET(%eax, %ecx, 4)
+ ret
+check_assignability:
+ PUSH eax // save arguments
+ PUSH ecx
+ PUSH edx
+ subl LITERAL(8), %esp // alignment padding
+ .cfi_adjust_cfa_offset 8
+ pushl CLASS_OFFSET(%edx) // pass arg2 - type of the value to be stored
+ .cfi_adjust_cfa_offset 4
+ PUSH ebx // pass arg1 - component type of the array
+ call SYMBOL(artIsAssignableFromCode) // (Class* a, Class* b)
+ addl LITERAL(16), %esp // pop arguments
+ .cfi_adjust_cfa_offset -16
+ testl %eax, %eax
+ jz throw_array_store_exception
+ POP edx
+ POP ecx
+ POP eax
+ movl %edx, OBJECT_ARRAY_DATA_OFFSET(%eax, %ecx, 4) // do the aput
+ movl %fs:THREAD_CARD_TABLE_OFFSET, %edx
+ shrl LITERAL(7), %eax
+ movb %dl, (%edx, %eax)
+ ret
+throw_array_store_exception:
+ POP edx
+ POP ecx
+ POP eax
+ SETUP_SAVE_ALL_CALLEE_SAVE_FRAME // save all registers as basis for long jump context
+ mov %esp, %ecx
+ // Outgoing argument set up
+ PUSH ecx // pass SP
+ pushl %fs:THREAD_SELF_OFFSET // pass Thread::Current()
+ .cfi_adjust_cfa_offset 4
+ PUSH edx // pass arg2 - value
+ PUSH eax // pass arg1 - array
+ call SYMBOL(artThrowArrayStoreException) // (array, value, Thread*, SP)
+ int3 // unreached
+END_FUNCTION art_quick_aput_obj
+
DEFINE_FUNCTION art_quick_memcpy
PUSH edx // pass arg3
PUSH ecx // pass arg2
@@ -497,9 +598,6 @@ DEFINE_FUNCTION art_quick_memcpy
ret
END_FUNCTION art_quick_memcpy
-TWO_ARG_DOWNCALL art_quick_check_cast, artCheckCastFromCode, RETURN_IF_EAX_ZERO
-TWO_ARG_DOWNCALL art_quick_can_put_array_element, artCanPutArrayElementFromCode, RETURN_IF_EAX_ZERO
-
NO_ARG_DOWNCALL art_quick_test_suspend, artTestSuspendFromCode, ret
DEFINE_FUNCTION art_quick_fmod
@@ -586,30 +684,30 @@ check_arg2:
END_FUNCTION art_quick_idivmod
DEFINE_FUNCTION art_quick_ldiv
- subl LITERAL(12), %esp // alignment padding
+ subl LITERAL(12), %esp // alignment padding
.cfi_adjust_cfa_offset 12
PUSH ebx // pass arg4 b.hi
PUSH edx // pass arg3 b.lo
PUSH ecx // pass arg2 a.hi
- PUSH eax // pass arg1 a.lo
- call SYMBOL(artLdivFromCode) // (jlong a, jlong b)
- addl LITERAL(28), %esp // pop arguments
+ PUSH eax // pass arg1 a.lo
+ call SYMBOL(artLdiv) // (jlong a, jlong b)
+ addl LITERAL(28), %esp // pop arguments
.cfi_adjust_cfa_offset -28
ret
END_FUNCTION art_quick_ldiv
-DEFINE_FUNCTION art_quick_ldivmod
- subl LITERAL(12), %esp // alignment padding
+DEFINE_FUNCTION art_quick_lmod
+ subl LITERAL(12), %esp // alignment padding
.cfi_adjust_cfa_offset 12
PUSH ebx // pass arg4 b.hi
PUSH edx // pass arg3 b.lo
PUSH ecx // pass arg2 a.hi
- PUSH eax // pass arg1 a.lo
- call SYMBOL(artLdivmodFromCode) // (jlong a, jlong b)
- addl LITERAL(28), %esp // pop arguments
+ PUSH eax // pass arg1 a.lo
+ call SYMBOL(artLmod) // (jlong a, jlong b)
+ addl LITERAL(28), %esp // pop arguments
.cfi_adjust_cfa_offset -28
ret
-END_FUNCTION art_quick_ldivmod
+END_FUNCTION art_quick_lmod
DEFINE_FUNCTION art_quick_lmul
imul %eax, %ebx // ebx = a.lo(eax) * b.hi(ebx)
diff --git a/runtime/arch/x86/thread_x86.cc b/runtime/arch/x86/thread_x86.cc
index 7e0aee0..42789cb 100644
--- a/runtime/arch/x86/thread_x86.cc
+++ b/runtime/arch/x86/thread_x86.cc
@@ -134,6 +134,7 @@ void Thread::InitCpu() {
// Sanity check other offsets.
CHECK_EQ(THREAD_EXCEPTION_OFFSET, OFFSETOF_MEMBER(Thread, exception_));
+ CHECK_EQ(THREAD_CARD_TABLE_OFFSET, OFFSETOF_MEMBER(Thread, card_table_));
CHECK_EQ(THREAD_ID_OFFSET, OFFSETOF_MEMBER(Thread, thin_lock_thread_id_));
}
diff --git a/runtime/asm_support.h b/runtime/asm_support.h
index d2eaf8e..a6700bc 100644
--- a/runtime/asm_support.h
+++ b/runtime/asm_support.h
@@ -22,8 +22,16 @@
#define SUSPEND_CHECK_INTERVAL (1000)
// Offsets within java.lang.Object.
+#define CLASS_OFFSET 0
#define LOCK_WORD_OFFSET 4
+// Offsets within java.lang.Class.
+#define CLASS_COMPONENT_TYPE_OFFSET 12
+
+// Array offsets.
+#define ARRAY_LENGTH_OFFSET 8
+#define OBJECT_ARRAY_DATA_OFFSET 12
+
// Offsets within java.lang.String.
#define STRING_VALUE_OFFSET 8
#define STRING_COUNT_OFFSET 12
diff --git a/runtime/entrypoints/quick/quick_cast_entrypoints.cc b/runtime/entrypoints/quick/quick_cast_entrypoints.cc
index 9ffa736..ae53d6c 100644
--- a/runtime/entrypoints/quick/quick_cast_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_cast_entrypoints.cc
@@ -14,11 +14,8 @@
* limitations under the License.
*/
-#include "callee_save_frame.h"
-#include "entrypoints/entrypoint_utils.h"
#include "mirror/class-inl.h"
#include "mirror/object-inl.h"
-#include "mirror/object_array-inl.h"
namespace art {
@@ -31,38 +28,4 @@ extern "C" uint32_t artIsAssignableFromCode(const mirror::Class* klass,
return klass->IsAssignableFrom(ref_class) ? 1 : 0;
}
-// Check whether it is safe to cast one class to the other, throw exception and return -1 on failure
-extern "C" int artCheckCastFromCode(mirror::Class* src_type, mirror::Class* dest_type,
- Thread* self, mirror::ArtMethod** sp)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- DCHECK(src_type->IsClass()) << PrettyClass(src_type);
- DCHECK(dest_type->IsClass()) << PrettyClass(dest_type);
- if (LIKELY(dest_type->IsAssignableFrom(src_type))) {
- return 0; // Success
- } else {
- FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- ThrowClassCastException(dest_type, src_type);
- return -1; // Failure
- }
-}
-
-// Tests whether 'element' can be assigned into an array of type 'array_class'.
-// Returns 0 on success and -1 if an exception is pending.
-extern "C" int artCanPutArrayElementFromCode(const mirror::Object* element,
- const mirror::Class* array_class,
- Thread* self, mirror::ArtMethod** sp)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- DCHECK(array_class != NULL);
- // element can't be NULL as we catch this is screened in runtime_support
- mirror::Class* element_class = element->GetClass();
- mirror::Class* component_type = array_class->GetComponentType();
- if (LIKELY(component_type->IsAssignableFrom(element_class))) {
- return 0; // Success
- } else {
- FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- ThrowArrayStoreException(element_class, array_class);
- return -1; // Failure
- }
-}
-
} // namespace art
diff --git a/runtime/entrypoints/quick/quick_entrypoints.h b/runtime/entrypoints/quick/quick_entrypoints.h
index 9d3b8ef..e9964ad 100644
--- a/runtime/entrypoints/quick/quick_entrypoints.h
+++ b/runtime/entrypoints/quick/quick_entrypoints.h
@@ -48,7 +48,6 @@ struct PACKED(4) QuickEntryPoints {
// Cast
uint32_t (*pInstanceofNonTrivial)(const mirror::Class*, const mirror::Class*);
- void (*pCanPutArrayElement)(void*, void*);
void (*pCheckCast)(void*, void*);
// DexCache
@@ -71,7 +70,10 @@ struct PACKED(4) QuickEntryPoints {
void* (*pGetObjInstance)(uint32_t, void*);
void* (*pGetObjStatic)(uint32_t);
- // FillArray
+ // Array
+ void (*pAputObjectWithNullAndBoundCheck)(void*, uint32_t, void*); // array, index, src
+ void (*pAputObjectWithBoundCheck)(void*, uint32_t, void*); // array, index, src
+ void (*pAputObject)(void*, uint32_t, void*); // array, index, src
void (*pHandleFillArrayData)(void*, void*);
// JNI
@@ -103,7 +105,7 @@ struct PACKED(4) QuickEntryPoints {
int64_t (*pD2l)(double);
int64_t (*pF2l)(float);
int64_t (*pLdiv)(int64_t, int64_t);
- int64_t (*pLdivmod)(int64_t, int64_t);
+ int64_t (*pLmod)(int64_t, int64_t);
int64_t (*pLmul)(int64_t, int64_t);
uint64_t (*pShlLong)(uint64_t, uint32_t);
uint64_t (*pShrLong)(uint64_t, uint32_t);
diff --git a/runtime/entrypoints/quick/quick_math_entrypoints.cc b/runtime/entrypoints/quick/quick_math_entrypoints.cc
index 0bfe59d..014aad3 100644
--- a/runtime/entrypoints/quick/quick_math_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_math_entrypoints.cc
@@ -62,15 +62,15 @@ int CmplDouble(double a, double b) {
return -1;
}
-extern "C" int64_t artLmulFromCode(int64_t a, int64_t b) {
+extern "C" int64_t artLmul(int64_t a, int64_t b) {
return a * b;
}
-extern "C" int64_t artLdivFromCode(int64_t a, int64_t b) {
+extern "C" int64_t artLdiv(int64_t a, int64_t b) {
return a / b;
}
-extern "C" int64_t artLdivmodFromCode(int64_t a, int64_t b) {
+extern "C" int64_t artLmod(int64_t a, int64_t b) {
return a % b;
}
diff --git a/runtime/entrypoints/quick/quick_throw_entrypoints.cc b/runtime/entrypoints/quick/quick_throw_entrypoints.cc
index f67b2fc..31eacac 100644
--- a/runtime/entrypoints/quick/quick_throw_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_throw_entrypoints.cc
@@ -15,8 +15,9 @@
*/
#include "callee_save_frame.h"
+#include "common_throws.h"
#include "entrypoints/entrypoint_utils.h"
-#include "mirror/object.h"
+#include "mirror/object-inl.h"
#include "object_utils.h"
#include "thread.h"
#include "well_known_classes.h"
@@ -95,4 +96,21 @@ extern "C" void artThrowNoSuchMethodFromCode(int32_t method_idx, Thread* self,
self->QuickDeliverException();
}
+extern "C" void artThrowClassCastException(mirror::Class* dest_type, mirror::Class* src_type,
+ Thread* self, mirror::ArtMethod** sp)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ FinishCalleeSaveFrameSetup(self, sp, Runtime::kSaveAll);
+ CHECK(!dest_type->IsAssignableFrom(src_type));
+ ThrowClassCastException(dest_type, src_type);
+ self->QuickDeliverException();
+}
+
+extern "C" void artThrowArrayStoreException(mirror::Object* array, mirror::Object* value,
+ Thread* self, mirror::ArtMethod** sp)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ FinishCalleeSaveFrameSetup(self, sp, Runtime::kSaveAll);
+ ThrowArrayStoreException(value->GetClass(), array->GetClass());
+ self->QuickDeliverException();
+}
+
} // namespace art
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index 586151d..dbc6f57 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -247,7 +247,7 @@ class MANAGED Class : public StaticStorageBase {
} else {
Class* component = GetComponentType();
if (component->IsPrimitive()) {
- return false;
+ return true;
} else {
return component->CannotBeAssignedFromOtherTypes();
}
@@ -346,14 +346,18 @@ class MANAGED Class : public StaticStorageBase {
bool IsArtMethodClass() const;
+ static MemberOffset ComponentTypeOffset() {
+ return OFFSET_OF_OBJECT_MEMBER(Class, component_type_);
+ }
+
Class* GetComponentType() const {
- return GetFieldObject<Class*>(OFFSET_OF_OBJECT_MEMBER(Class, component_type_), false);
+ return GetFieldObject<Class*>(ComponentTypeOffset(), false);
}
void SetComponentType(Class* new_component_type) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
DCHECK(GetComponentType() == NULL);
DCHECK(new_component_type != NULL);
- SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, component_type_), new_component_type, false);
+ SetFieldObject(ComponentTypeOffset(), new_component_type, false);
}
size_t GetComponentSize() const {
diff --git a/runtime/mirror/object_test.cc b/runtime/mirror/object_test.cc
index b8765af..1e610f2 100644
--- a/runtime/mirror/object_test.cc
+++ b/runtime/mirror/object_test.cc
@@ -71,12 +71,20 @@ class ObjectTest : public CommonTest {
// Keep the assembly code in sync
TEST_F(ObjectTest, AsmConstants) {
- ASSERT_EQ(STRING_VALUE_OFFSET, String::ValueOffset().Int32Value());
- ASSERT_EQ(STRING_COUNT_OFFSET, String::CountOffset().Int32Value());
- ASSERT_EQ(STRING_OFFSET_OFFSET, String::OffsetOffset().Int32Value());
- ASSERT_EQ(STRING_DATA_OFFSET, Array::DataOffset(sizeof(uint16_t)).Int32Value());
+ EXPECT_EQ(CLASS_OFFSET, Object::ClassOffset().Int32Value());
+ EXPECT_EQ(LOCK_WORD_OFFSET, Object::MonitorOffset().Int32Value());
- ASSERT_EQ(METHOD_CODE_OFFSET, ArtMethod::EntryPointFromCompiledCodeOffset().Int32Value());
+ EXPECT_EQ(CLASS_COMPONENT_TYPE_OFFSET, Class::ComponentTypeOffset().Int32Value());
+
+ EXPECT_EQ(ARRAY_LENGTH_OFFSET, Array::LengthOffset().Int32Value());
+ EXPECT_EQ(OBJECT_ARRAY_DATA_OFFSET, Array::DataOffset(sizeof(Object*)).Int32Value());
+
+ EXPECT_EQ(STRING_VALUE_OFFSET, String::ValueOffset().Int32Value());
+ EXPECT_EQ(STRING_COUNT_OFFSET, String::CountOffset().Int32Value());
+ EXPECT_EQ(STRING_OFFSET_OFFSET, String::OffsetOffset().Int32Value());
+ EXPECT_EQ(STRING_DATA_OFFSET, Array::DataOffset(sizeof(uint16_t)).Int32Value());
+
+ EXPECT_EQ(METHOD_CODE_OFFSET, ArtMethod::EntryPointFromCompiledCodeOffset().Int32Value());
}
TEST_F(ObjectTest, IsInSamePackage) {
diff --git a/runtime/thread.cc b/runtime/thread.cc
index de14dbb..3063658 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -1564,7 +1564,6 @@ static const EntryPointInfo gThreadEntryPointInfo[] = {
QUICK_ENTRY_POINT_INFO(pCheckAndAllocArray),
QUICK_ENTRY_POINT_INFO(pCheckAndAllocArrayWithAccessCheck),
QUICK_ENTRY_POINT_INFO(pInstanceofNonTrivial),
- QUICK_ENTRY_POINT_INFO(pCanPutArrayElement),
QUICK_ENTRY_POINT_INFO(pCheckCast),
QUICK_ENTRY_POINT_INFO(pInitializeStaticStorage),
QUICK_ENTRY_POINT_INFO(pInitializeTypeAndVerifyAccess),
@@ -1582,6 +1581,9 @@ static const EntryPointInfo gThreadEntryPointInfo[] = {
QUICK_ENTRY_POINT_INFO(pGet64Static),
QUICK_ENTRY_POINT_INFO(pGetObjInstance),
QUICK_ENTRY_POINT_INFO(pGetObjStatic),
+ QUICK_ENTRY_POINT_INFO(pAputObjectWithNullAndBoundCheck),
+ QUICK_ENTRY_POINT_INFO(pAputObjectWithBoundCheck),
+ QUICK_ENTRY_POINT_INFO(pAputObject),
QUICK_ENTRY_POINT_INFO(pHandleFillArrayData),
QUICK_ENTRY_POINT_INFO(pJniMethodStart),
QUICK_ENTRY_POINT_INFO(pJniMethodStartSynchronized),
@@ -1606,7 +1608,7 @@ static const EntryPointInfo gThreadEntryPointInfo[] = {
QUICK_ENTRY_POINT_INFO(pD2l),
QUICK_ENTRY_POINT_INFO(pF2l),
QUICK_ENTRY_POINT_INFO(pLdiv),
- QUICK_ENTRY_POINT_INFO(pLdivmod),
+ QUICK_ENTRY_POINT_INFO(pLmod),
QUICK_ENTRY_POINT_INFO(pLmul),
QUICK_ENTRY_POINT_INFO(pShlLong),
QUICK_ENTRY_POINT_INFO(pShrLong),
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 6b1ff77..7d2ee19 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -506,17 +506,25 @@ bool MethodVerifier::ComputeWidthsAndCountOps() {
while (dex_pc < insns_size) {
Instruction::Code opcode = inst->Opcode();
- if (opcode == Instruction::NEW_INSTANCE) {
- new_instance_count++;
- } else if (opcode == Instruction::MONITOR_ENTER) {
- monitor_enter_count++;
- } else if (opcode == Instruction::CHECK_CAST) {
- has_check_casts_ = true;
- } else if ((inst->Opcode() == Instruction::INVOKE_VIRTUAL) ||
- (inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE) ||
- (inst->Opcode() == Instruction::INVOKE_INTERFACE) ||
- (inst->Opcode() == Instruction::INVOKE_INTERFACE_RANGE)) {
- has_virtual_or_interface_invokes_ = true;
+ switch (opcode) {
+ case Instruction::APUT_OBJECT:
+ case Instruction::CHECK_CAST:
+ has_check_casts_ = true;
+ break;
+ case Instruction::INVOKE_VIRTUAL:
+ case Instruction::INVOKE_VIRTUAL_RANGE:
+ case Instruction::INVOKE_INTERFACE:
+ case Instruction::INVOKE_INTERFACE_RANGE:
+ has_virtual_or_interface_invokes_ = true;
+ break;
+ case Instruction::MONITOR_ENTER:
+ monitor_enter_count++;
+ break;
+ case Instruction::NEW_INSTANCE:
+ new_instance_count++;
+ break;
+ default:
+ break;
}
size_t inst_size = inst->SizeInCodeUnits();
insn_flags_[dex_pc].SetLengthInCodeUnits(inst_size);
@@ -3940,18 +3948,32 @@ MethodVerifier::MethodSafeCastSet* MethodVerifier::GenerateSafeCastSet() {
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());
+ Instruction::Code code = inst->Opcode();
+ if ((code == Instruction::CHECK_CAST) || (code == Instruction::APUT_OBJECT)) {
+ uint32_t dex_pc = inst->GetDexPc(code_item_->insns_);
+ RegisterLine* line = reg_table_.GetLine(dex_pc);
+ bool is_safe_cast = false;
+ if (code == Instruction::CHECK_CAST) {
+ const RegType& reg_type(line->GetRegisterType(inst->VRegA_21c()));
+ const RegType& cast_type = ResolveClassAndCheckAccess(inst->VRegB_21c());
+ is_safe_cast = cast_type.IsStrictlyAssignableFrom(reg_type);
+ } else {
+ const RegType& array_type(line->GetRegisterType(inst->VRegB_23x()));
+ // We only know its safe to assign to an array if the array type is precise. For example,
+ // an Object[] can have any type of object stored in it, but it may also be assigned a
+ // String[] in which case the stores need to be of Strings.
+ if (array_type.IsPreciseReference()) {
+ const RegType& value_type(line->GetRegisterType(inst->VRegA_23x()));
+ const RegType& component_type(reg_types_.GetComponentType(array_type, class_loader_));
+ is_safe_cast = component_type.IsStrictlyAssignableFrom(value_type);
+ }
+ }
+ if (is_safe_cast) {
+ if (mscs.get() == NULL) {
+ mscs.reset(new MethodSafeCastSet());
+ }
+ mscs->insert(dex_pc);
}
- mscs->insert(dex_pc);
}
}
return mscs.release();
diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h
index 7f33741..57fde1d 100644
--- a/runtime/verifier/method_verifier.h
+++ b/runtime/verifier/method_verifier.h
@@ -724,10 +724,12 @@ class MethodVerifier {
// running and the verifier is called from the class linker.
const bool allow_soft_failures_;
- // Indicates if the method being verified contains at least one check-cast instruction.
+ // Indicates the method being verified contains at least one check-cast or aput-object
+ // instruction. Aput-object operations implicitly check for array-store exceptions, similar to
+ // check-cast.
bool has_check_casts_;
- // Indicates if the method being verified contains at least one invoke-virtual/range
+ // Indicates the method being verified contains at least one invoke-virtual/range
// or invoke-interface/range.
bool has_virtual_or_interface_invokes_;
};
diff --git a/runtime/verifier/reg_type_cache.cc b/runtime/verifier/reg_type_cache.cc
index fd70300..446dd00 100644
--- a/runtime/verifier/reg_type_cache.cc
+++ b/runtime/verifier/reg_type_cache.cc
@@ -531,8 +531,9 @@ const ConstantType& RegTypeCache::FromCat2ConstHi(int32_t value, bool precise) {
}
const RegType& RegTypeCache::GetComponentType(const RegType& array, mirror::ClassLoader* loader) {
- CHECK(array.IsArrayTypes());
- if (array.IsUnresolvedTypes()) {
+ if (!array.IsArrayTypes()) {
+ return Conflict();
+ } else if (array.IsUnresolvedTypes()) {
const std::string& descriptor(array.GetDescriptor());
const std::string component(descriptor.substr(1, descriptor.size() - 1));
return FromDescriptor(loader, component.c_str(), false);