Refactor code in mterp and nterp to handle all cases of missing class.
This is to handle the case the type of a field is missing, and where we
only throw an exception when we assign a non-null value.
Bug: 79751666
Bug: 112676029
Bug: 176960283
Test: test.py
Change-Id: I9c233f271eea7ae4a8028fb727d5c49c7c45feac
diff --git a/runtime/interpreter/mterp/arm64ng/object.S b/runtime/interpreter/mterp/arm64ng/object.S
index ea882c2..0fd33d3 100644
--- a/runtime/interpreter/mterp/arm64ng/object.S
+++ b/runtime/interpreter/mterp/arm64ng/object.S
@@ -97,6 +97,7 @@
mov x0, xSELF
ldr x1, [sp]
mov x2, xPC
+ mov x3, #0
EXPORT_PC
bl nterp_get_instance_field_offset
tbz w0, #31, .L${opcode}_resume
@@ -200,20 +201,23 @@
// It does not matter to which `.L${opcode}_resume` the slow path returns.
% slow_path = "nterp_op_iput_helper_" + store + wide + is_object
% add_helper(lambda: op_iput_slow_path(volatile_store, wide, is_object), slow_path)
+ ubfx w1, wINST, #8, #4 // w1<- A
+ .if $wide
+ GET_VREG_WIDE x26, w1 // x26<- fp[A]/fp[A+1]
+ .else
+ GET_VREG w26, w1 // w26 <- v[A]
+ .endif
// Fast-path which gets the field from thread-local cache.
FETCH_FROM_THREAD_CACHE x0, ${slow_path}
.L${opcode}_resume:
lsr w2, wINST, #12 // w2<- B
- ubfx w1, wINST, #8, #4 // w1<- A
GET_VREG w2, w2 // vB (object we're operating on)
cbz w2, common_errNullObject
.if $wide
- GET_VREG_WIDE x1, w1 // x1<- fp[A]/fp[A+1]
- $store x1, [x2, x0]
+ $store x26, [x2, x0]
.else
- GET_VREG w1, w1 // w1 <- v[A]
- $store w1, [x2, x0]
- WRITE_BARRIER_IF_OBJECT $is_object, w1, w2, .L${opcode}_skip_write_barrier
+ $store w26, [x2, x0]
+ WRITE_BARRIER_IF_OBJECT $is_object, w26, w2, .L${opcode}_skip_write_barrier
.endif
FETCH_ADVANCE_INST 2
GET_INST_OPCODE ip
@@ -223,22 +227,24 @@
mov x0, xSELF
ldr x1, [sp]
mov x2, xPC
+ .if $is_object
+ mov x3, x26
+ .else
+ mov x3, #0
+ .endif
EXPORT_PC
bl nterp_get_instance_field_offset
tbz w0, #31, .L${opcode}_resume
CLEAR_INSTANCE_VOLATILE_MARKER w0
lsr w2, wINST, #12 // w2<- B
- ubfx w1, wINST, #8, #4 // w1<- A
GET_VREG w2, w2 // vB (object we're operating on)
cbz w2, common_errNullObject
add x3, x2, x0
.if $wide
- GET_VREG_WIDE x1, w1 // x1<- fp[A]/fp[A+1]
- $volatile_store x1, [x3]
+ $volatile_store x26, [x3]
.else
- GET_VREG w1, w1 // w1 <- v[A]
- $volatile_store w1, [x3]
- WRITE_BARRIER_IF_OBJECT $is_object, w1, w2, .L${opcode}_slow_path_skip_write_barrier
+ $volatile_store w26, [x3]
+ WRITE_BARRIER_IF_OBJECT $is_object, w26, w2, .L${opcode}_slow_path_skip_write_barrier
.endif
FETCH_ADVANCE_INST 2
GET_INST_OPCODE ip
@@ -341,6 +347,7 @@
mov x0, xSELF
ldr x1, [sp]
mov x2, xPC
+ mov x3, #0
EXPORT_PC
bl nterp_get_static_field
tbz x0, #0, .L${opcode}_resume
@@ -393,21 +400,24 @@
// It does not matter to which `.L${opcode}_resume` the slow path returns.
% slow_path = "nterp_op_sput_helper_" + store + wide + is_object
% add_helper(lambda: op_sput_slow_path(volatile_store, wide, is_object), slow_path)
+ lsr w2, wINST, #8 // w2 <- A
+ .if $wide
+ GET_VREG_WIDE x26, w2 // x26 <- v[A]
+ .else
+ GET_VREG w26, w2 // w26 <- v[A]
+ .endif
// Fast-path which gets the field from thread-local cache.
FETCH_FROM_THREAD_CACHE x0, ${slow_path}
.L${opcode}_resume:
ldr w1, [x0, #ART_FIELD_OFFSET_OFFSET]
- lsr w2, wINST, #8 // w2 <- A
ldr w0, [x0, #ART_FIELD_DECLARING_CLASS_OFFSET]
cbnz wMR, .L${opcode}_read_barrier
.L${opcode}_resume_after_read_barrier:
.if $wide
- GET_VREG_WIDE x2, w2 // x2 <- v[A]
- $store x2, [x0, x1]
+ $store x26, [x0, x1]
.else
- GET_VREG w2, w2 // w2 <- v[A]
- $store w2, [x0, x1]
- WRITE_BARRIER_IF_OBJECT $is_object, w2, w0, .L${opcode}_skip_write_barrier
+ $store w26, [x0, x1]
+ WRITE_BARRIER_IF_OBJECT $is_object, w26, w0, .L${opcode}_skip_write_barrier
.endif
FETCH_ADVANCE_INST 2
GET_INST_OPCODE ip
@@ -420,23 +430,25 @@
mov x0, xSELF
ldr x1, [sp]
mov x2, xPC
+ .if $is_object
+ mov x3, x26
+ .else
+ mov x3, #0
+ .endif
EXPORT_PC
bl nterp_get_static_field
tbz x0, #0, .L${opcode}_resume
CLEAR_STATIC_VOLATILE_MARKER x0
ldr w1, [x0, #ART_FIELD_OFFSET_OFFSET]
- lsr w2, wINST, #8 // w2 <- A
ldr w0, [x0, #ART_FIELD_DECLARING_CLASS_OFFSET]
cbnz wMR, .L${opcode}_slow_path_read_barrier
.L${opcode}_slow_path_resume_after_read_barrier:
add x1, x0, x1
.if $wide
- GET_VREG_WIDE x2, w2 // x2 <- v[A]
- $volatile_store x2, [x1]
+ $volatile_store x26, [x1]
.else
- GET_VREG w2, w2 // w2 <- v[A]
- $volatile_store w2, [x1]
- WRITE_BARRIER_IF_OBJECT $is_object, w2, w0, .L${opcode}_slow_path_skip_write_barrier
+ $volatile_store w26, [x1]
+ WRITE_BARRIER_IF_OBJECT $is_object, w26, w0, .L${opcode}_slow_path_skip_write_barrier
.endif
FETCH_ADVANCE_INST 2
GET_INST_OPCODE ip
diff --git a/runtime/interpreter/mterp/armng/object.S b/runtime/interpreter/mterp/armng/object.S
index 29324d2..abcad5d 100644
--- a/runtime/interpreter/mterp/armng/object.S
+++ b/runtime/interpreter/mterp/armng/object.S
@@ -106,6 +106,7 @@
mov r0, rSELF
ldr r1, [sp]
mov r2, rPC
+ mov r3, #0
EXPORT_PC
bl nterp_get_instance_field_offset
cmp r0, #0
@@ -222,23 +223,26 @@
// It does not matter to which `.L${opcode}_resume` the slow path returns.
% slow_path = "nterp_op_iput_helper_" + store + wide + is_object
% add_helper(lambda: op_iput_slow_path(store, wide, is_object), slow_path)
+ .if !$wide
+ ubfx r4, rINST, #8, #4 // r4<- A
+ GET_VREG r4, r4 // r4 <- v[A]
+ .endif
// Fast-path which gets the field from thread-local cache.
FETCH_FROM_THREAD_CACHE r0, ${slow_path}
.L${opcode}_resume:
- lsr r4, rINST, #12 // r2<- B
- ubfx r1, rINST, #8, #4 // r1<- A
- GET_VREG r4, r4 // vB (object we're operating on)
- cmp r4, #0
+ lsr r1, rINST, #12 // r1<- B
+ GET_VREG r1, r1 // vB (object we're operating on)
+ cmp r1, #0
beq common_errNullObject
.if $wide
- VREG_INDEX_TO_ADDR r1, r1
- GET_VREG_WIDE_BY_ADDR r2, r3, r1 // fp[A] <- value
- add r4, r4, r0
- strd r2, r3, [r4]
+ ubfx r4, rINST, #8, #4 // r4<- A
+ VREG_INDEX_TO_ADDR r4, r4
+ GET_VREG_WIDE_BY_ADDR r2, r3, r4 // fp[A] <- value
+ add r1, r1, r0
+ strd r2, r3, [r1]
.else
- GET_VREG r1, r1 // r1 <- v[A]
- $store r1, [r4, r0]
- WRITE_BARRIER_IF_OBJECT $is_object, r1, r4, .L${opcode}_skip_write_barrier, r0
+ $store r4, [r1, r0]
+ WRITE_BARRIER_IF_OBJECT $is_object, r4, r1, .L${opcode}_skip_write_barrier, r0
.endif
FETCH_ADVANCE_INST 2
GET_INST_OPCODE ip
@@ -248,17 +252,22 @@
mov r0, rSELF
ldr r1, [sp]
mov r2, rPC
+ .if $is_object
+ mov r3, r4
+ .else
+ mov r3, #0
+ .endif
EXPORT_PC
bl nterp_get_instance_field_offset
cmp r0, #0
bge .L${opcode}_resume
CLEAR_INSTANCE_VOLATILE_MARKER r0
- lsr r4, rINST, #12 // r2<- B
+ .if $wide
+ lsr r4, rINST, #12 // r4<- B
ubfx r1, rINST, #8, #4 // r1<- A
GET_VREG r4, r4 // vB (object we're operating on)
cmp r4, #0
beq common_errNullObject
- .if $wide
VREG_INDEX_TO_ADDR r1, r1
GET_VREG_WIDE_BY_ADDR r2, r3, r1
add ip, r4, r0
@@ -266,11 +275,14 @@
ATOMIC_STORE64 ip, r2, r3, r0, r1, .L${opcode}_slow_path_atomic_store
dmb ish
.else
- GET_VREG r1, r1 // r1 <- v[A]
+ lsr r1, rINST, #12 // r4<- B
+ GET_VREG r1, r1 // vB (object we're operating on)
+ cmp r1, #0
+ beq common_errNullObject
dmb ish
- $store r1, [r4, r0]
+ $store r4, [r1, r0]
dmb ish
- WRITE_BARRIER_IF_OBJECT $is_object, r1, r4, .L${opcode}_slow_path_skip_write_barrier, r0
+ WRITE_BARRIER_IF_OBJECT $is_object, r4, r1, .L${opcode}_slow_path_skip_write_barrier, r0
.endif
FETCH_ADVANCE_INST 2
GET_INST_OPCODE ip
@@ -380,6 +392,7 @@
mov r0, rSELF
ldr r1, [sp]
mov r2, rPC
+ mov r3, #0
EXPORT_PC
bl nterp_get_static_field
tst r0, #1
@@ -439,24 +452,27 @@
// It does not matter to which `.L${opcode}_resume` the slow path returns.
% slow_path = "nterp_op_sput_helper_" + store + wide + is_object
% add_helper(lambda: op_sput_slow_path(store, wide, is_object), slow_path)
+ .if !$wide
+ lsr r4, rINST, #8 // r4 <- A
+ GET_VREG r4, r4 // r4 <- v[A]
+ .endif
// Fast-path which gets the field from thread-local cache.
FETCH_FROM_THREAD_CACHE r0, ${slow_path}
.L${opcode}_resume:
ldr r1, [r0, #ART_FIELD_OFFSET_OFFSET]
- lsr r2, rINST, #8 // r2 <- A
ldr r0, [r0, #ART_FIELD_DECLARING_CLASS_OFFSET]
cmp rMR, #0
bne .L${opcode}_read_barrier
.L${opcode}_resume_after_read_barrier:
.if $wide
+ lsr r2, rINST, #8 // r2 <- A
VREG_INDEX_TO_ADDR r2, r2
GET_VREG_WIDE_BY_ADDR r2, r3, r2 // fp[A] <- value
add r0, r0, r1
strd r2, r3, [r0]
.else
- GET_VREG r2, r2 // r2 <- v[A]
- $store r2, [r0, r1]
- WRITE_BARRIER_IF_OBJECT $is_object, r2, r0, .L${opcode}_skip_write_barrier, r1
+ $store r4, [r0, r1]
+ WRITE_BARRIER_IF_OBJECT $is_object, r4, r0, .L${opcode}_skip_write_barrier, r1
.endif
FETCH_ADVANCE_INST 2
GET_INST_OPCODE ip
@@ -469,18 +485,23 @@
mov r0, rSELF
ldr r1, [sp]
mov r2, rPC
+ .if $is_object
+ mov r3, r4
+ .else
+ mov r3, #0
+ .endif
EXPORT_PC
bl nterp_get_static_field
tst r0, #1
beq .L${opcode}_resume
CLEAR_STATIC_VOLATILE_MARKER r0
ldr r1, [r0, #ART_FIELD_OFFSET_OFFSET]
- lsr r2, rINST, #8 // r2 <- A
ldr r0, [r0, #ART_FIELD_DECLARING_CLASS_OFFSET]
cmp rMR, #0
bne .L${opcode}_slow_path_read_barrier
.L${opcode}_slow_path_resume_after_read_barrier:
.if $wide
+ lsr r2, rINST, #8 // r2 <- A
VREG_INDEX_TO_ADDR r2, r2
GET_VREG_WIDE_BY_ADDR r2, r3, r2
add ip, r0, r1
@@ -488,11 +509,10 @@
ATOMIC_STORE64 ip, r2, r3, r0, r1, .L${opcode}_slow_path_atomic_store
dmb ish
.else
- GET_VREG r2, r2 // r2 <- v[A]
dmb ish
- $store r2, [r0, r1]
+ $store r4, [r0, r1]
dmb ish
- WRITE_BARRIER_IF_OBJECT $is_object, r2, r0, .L${opcode}_slow_path_skip_write_barrier, r1
+ WRITE_BARRIER_IF_OBJECT $is_object, r4, r0, .L${opcode}_slow_path_skip_write_barrier, r1
.endif
FETCH_ADVANCE_INST 2
GET_INST_OPCODE ip
diff --git a/runtime/interpreter/mterp/mterp.cc b/runtime/interpreter/mterp/mterp.cc
index 7a47282..af68756 100644
--- a/runtime/interpreter/mterp/mterp.cc
+++ b/runtime/interpreter/mterp/mterp.cc
@@ -661,6 +661,15 @@
DCHECK(self->IsExceptionPending());
return false;
}
+ constexpr bool kIsPrimitive = (kAccessType & FindFieldFlags::PrimitiveBit) != 0;
+ if (!kIsPrimitive) {
+ uint16_t vRegA = kIsStatic ? inst->VRegA_21c(inst_data) : inst->VRegA_22c(inst_data);
+ ObjPtr<mirror::Object> value = shadow_frame->GetVRegReference(vRegA);
+ if (value != nullptr && field->ResolveType() == nullptr) {
+ DCHECK(self->IsExceptionPending());
+ return false;
+ }
+ }
ObjPtr<mirror::Object> obj = kIsStatic
? field->GetDeclaringClass().Ptr()
: shadow_frame->GetVRegReference(inst->VRegB_22c(inst_data));
diff --git a/runtime/interpreter/mterp/nterp.cc b/runtime/interpreter/mterp/nterp.cc
index 1da8be6..20d8305 100644
--- a/runtime/interpreter/mterp/nterp.cc
+++ b/runtime/interpreter/mterp/nterp.cc
@@ -425,7 +425,8 @@
uint16_t field_index,
ArtMethod* caller,
bool is_static,
- bool is_put)
+ bool is_put,
+ size_t resolve_field_type) // Resolve if not zero
REQUIRES_SHARED(Locks::mutator_lock_) {
if (caller->SkipAccessChecks()) {
return class_linker->ResolveField(field_index, caller, is_static);
@@ -460,10 +461,17 @@
ThrowIllegalAccessErrorFinalField(caller, resolved_field);
return nullptr;
}
+ if (resolve_field_type != 0u && resolved_field->ResolveType() == nullptr) {
+ DCHECK(self->IsExceptionPending());
+ return nullptr;
+ }
return resolved_field;
}
-extern "C" size_t NterpGetStaticField(Thread* self, ArtMethod* caller, uint16_t* dex_pc_ptr)
+extern "C" size_t NterpGetStaticField(Thread* self,
+ ArtMethod* caller,
+ uint16_t* dex_pc_ptr,
+ size_t resolve_field_type) // Resolve if not zero
REQUIRES_SHARED(Locks::mutator_lock_) {
UpdateHotness(caller);
const Instruction* inst = Instruction::At(dex_pc_ptr);
@@ -475,7 +483,8 @@
field_index,
caller,
/* is_static */ true,
- /* is_put */ IsInstructionSPut(inst->Opcode()));
+ /* is_put */ IsInstructionSPut(inst->Opcode()),
+ resolve_field_type);
if (resolved_field == nullptr) {
DCHECK(self->IsExceptionPending());
@@ -504,7 +513,8 @@
extern "C" uint32_t NterpGetInstanceFieldOffset(Thread* self,
ArtMethod* caller,
- uint16_t* dex_pc_ptr)
+ uint16_t* dex_pc_ptr,
+ size_t resolve_field_type) // Resolve if not zero
REQUIRES_SHARED(Locks::mutator_lock_) {
UpdateHotness(caller);
const Instruction* inst = Instruction::At(dex_pc_ptr);
@@ -516,7 +526,8 @@
field_index,
caller,
/* is_static */ false,
- /* is_put */ IsInstructionIPut(inst->Opcode()));
+ /* is_put */ IsInstructionIPut(inst->Opcode()),
+ resolve_field_type);
if (resolved_field == nullptr) {
DCHECK(self->IsExceptionPending());
return 0;
diff --git a/runtime/interpreter/mterp/x86_64ng/main.S b/runtime/interpreter/mterp/x86_64ng/main.S
index 5611b04..fa5f4e4 100644
--- a/runtime/interpreter/mterp/x86_64ng/main.S
+++ b/runtime/interpreter/mterp/x86_64ng/main.S
@@ -1299,10 +1299,11 @@
.endif
ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
2:
+ EXPORT_PC
movq rSELF:THREAD_SELF_OFFSET, %rdi
movq 0(%rsp), %rsi
movq rPC, %rdx
- EXPORT_PC
+ movq $$0, %rcx
call nterp_get_static_field
// Clear the marker that we put for volatile fields. The x86 memory
// model doesn't require a barrier.
@@ -1331,10 +1332,11 @@
\store \rINST_reg, (%rax,%rdx,1)
ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
2:
+ EXPORT_PC
movq rSELF:THREAD_SELF_OFFSET, %rdi
movq 0(%rsp), %rsi
movq rPC, %rdx
- EXPORT_PC
+ movq $$0, %rcx
call nterp_get_static_field
testq MACRO_LITERAL(1), %rax
je 1b
@@ -1386,10 +1388,11 @@
OP_IPUT_INTERNAL \rINST_reg, \store, \wide
ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
2:
+ EXPORT_PC
movq rSELF:THREAD_SELF_OFFSET, %rdi
movq 0(%rsp), %rsi
movq rPC, %rdx
- EXPORT_PC
+ movq $$0, %rcx
call nterp_get_instance_field_offset
testl %eax, %eax
jns 1b
@@ -1419,10 +1422,11 @@
.endif
ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
2:
+ EXPORT_PC
movq rSELF:THREAD_SELF_OFFSET, %rdi
movq 0(%rsp), %rsi
movq rPC, %rdx
- EXPORT_PC
+ movq $$0, %rcx
call nterp_get_instance_field_offset
testl %eax, %eax
jns 1b
@@ -1667,22 +1671,22 @@
jmp 1b
NterpPutObjectInstanceField:
+ movzbq rINSTbl, %rbp # rcx <- BA
+ sarl $$4, %ebp # ebp <- B
+ GET_VREG %ebp, %rbp # vB (object we're operating on)
+ andb $$0xf, rINSTbl # rINST <- A
+ GET_VREG rINST, rINSTq # rINST <- v[A]
// Fast-path which gets the field from thread-local cache.
FETCH_FROM_THREAD_CACHE %rax, 2f
1:
- movzbq rINSTbl, %rcx # rcx <- BA
- sarl $$4, %ecx # ecx <- B
- GET_VREG %ecx, %rcx # vB (object we're operating on)
- testl %ecx, %ecx # is object null?
+ testl %ebp, %ebp # is object null?
je common_errNullObject
- andb $$0xf, rINSTbl # rINST <- A
- GET_VREG rINST, rINSTq # rINST <- v[A]
- movl rINST, (%rcx,%rax,1)
+ movl rINST, (%rbp,%rax,1)
testl rINST, rINST
je 4f
movq rSELF:THREAD_CARD_TABLE_OFFSET, %rax
- shrq $$CARD_TABLE_CARD_SHIFT, %rcx
- movb %al, (%rax, %rcx, 1)
+ shrq $$CARD_TABLE_CARD_SHIFT, %rbp
+ movb %al, (%rax, %rbp, 1)
4:
ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
2:
@@ -1690,24 +1694,19 @@
movq rSELF:THREAD_SELF_OFFSET, %rdi
movq 0(%rsp), %rsi
movq rPC, %rdx
- EXPORT_PC
+ movq rINSTq, %rcx
call nterp_get_instance_field_offset
testl %eax, %eax
jns 1b
- negl %eax
- movzbq rINSTbl, %rcx # rcx <- BA
- sarl $$4, %ecx # ecx <- B
- GET_VREG %ecx, %rcx # vB (object we're operating on)
- testl %ecx, %ecx # is object null?
+ testl %ebp, %ebp # is object null?
je common_errNullObject
- andb $$0xf, rINSTbl # rINST <- A
- GET_VREG rINST, rINSTq # rINST <- v[A]
- movl rINST, (%rcx,%rax,1)
+ negl %eax
+ movl rINST, (%rbp,%rax,1)
testl rINST, rINST
je 5f
movq rSELF:THREAD_CARD_TABLE_OFFSET, %rax
- shrq $$CARD_TABLE_CARD_SHIFT, %rcx
- movb %al, (%rcx, %rax, 1)
+ shrq $$CARD_TABLE_CARD_SHIFT, %rbp
+ movb %al, (%rbp, %rax, 1)
5:
lock addl $$0, (%rsp)
ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
@@ -1733,7 +1732,7 @@
movq rSELF:THREAD_SELF_OFFSET, %rdi
movq 0(%rsp), %rsi
movq rPC, %rdx
- EXPORT_PC
+ movq $$0, %rcx
call nterp_get_instance_field_offset
testl %eax, %eax
jns 1b
@@ -1747,6 +1746,7 @@
jmp 4b
NterpPutObjectStaticField:
+ GET_VREG %ebp, rINSTq
// Fast-path which gets the field from thread-local cache.
FETCH_FROM_THREAD_CACHE %rax, 2f
1:
@@ -1755,9 +1755,8 @@
cmpq $$0, rSELF:THREAD_READ_BARRIER_MARK_REG00_OFFSET
jne 3f
5:
- GET_VREG %ecx, rINSTq
- movl %ecx, (%eax, %edx, 1)
- testl %ecx, %ecx
+ movl %ebp, (%eax, %edx, 1)
+ testl %ebp, %ebp
je 4f
movq rSELF:THREAD_CARD_TABLE_OFFSET, %rcx
shrq $$CARD_TABLE_CARD_SHIFT, %rax
@@ -1765,10 +1764,11 @@
4:
ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
2:
+ EXPORT_PC
movq rSELF:THREAD_SELF_OFFSET, %rdi
movq 0(%rsp), %rsi
movq rPC, %rdx
- EXPORT_PC
+ movq %rbp, %rcx
call nterp_get_static_field
testq MACRO_LITERAL(1), %rax
je 1b
@@ -1778,10 +1778,8 @@
cmpq $$0, rSELF:THREAD_READ_BARRIER_MARK_REG00_OFFSET
jne 7f
6:
- movzbl rINSTbl, %ecx
- GET_VREG %ecx, %rcx
- movl %ecx, (%eax, %edx, 1)
- testl %ecx, %ecx
+ movl %ebp, (%eax, %edx, 1)
+ testl %ebp, %ebp
je 8f
movq rSELF:THREAD_CARD_TABLE_OFFSET, %rcx
shrq $$CARD_TABLE_CARD_SHIFT, %rax
@@ -1812,10 +1810,11 @@
SET_VREG_OBJECT %eax, rINSTq # fp[A] <- value
ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
2:
+ EXPORT_PC
movq rSELF:THREAD_SELF_OFFSET, %rdi
movq 0(%rsp), %rsi
movq rPC, %rdx
- EXPORT_PC
+ movq $$0, %rcx
call nterp_get_static_field
andq $$-2, %rax
jmp 1b
diff --git a/test/814-large-field-offsets/expected-stderr.txt b/test/814-large-field-offsets/expected-stderr.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/814-large-field-offsets/expected-stderr.txt
diff --git a/test/814-large-field-offsets/expected-stdout.txt b/test/814-large-field-offsets/expected-stdout.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/814-large-field-offsets/expected-stdout.txt
diff --git a/test/814-large-field-offsets/info.txt b/test/814-large-field-offsets/info.txt
new file mode 100644
index 0000000..eb2351f
--- /dev/null
+++ b/test/814-large-field-offsets/info.txt
@@ -0,0 +1 @@
+Regression test checking that we throw NPE on large field offsets.
diff --git a/test/814-large-field-offsets/src/Main.java b/test/814-large-field-offsets/src/Main.java
new file mode 100644
index 0000000..36d4f5e
--- /dev/null
+++ b/test/814-large-field-offsets/src/Main.java
@@ -0,0 +1,361 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class Main {
+
+ Object i0000, i0001, i0002, i0003, i0004, i0005, i0006, i0007, i0008, i0009;
+ Object i0010, i0011, i0012, i0013, i0014, i0015, i0016, i0017, i0018, i0019;
+ Object i0020, i0021, i0022, i0023, i0024, i0025, i0026, i0027, i0028, i0029;
+ Object i0030, i0031, i0032, i0033, i0034, i0035, i0036, i0037, i0038, i0039;
+ Object i0040, i0041, i0042, i0043, i0044, i0045, i0046, i0047, i0048, i0049;
+ Object i0050, i0051, i0052, i0053, i0054, i0055, i0056, i0057, i0058, i0059;
+ Object i0060, i0061, i0062, i0063, i0064, i0065, i0066, i0067, i0068, i0069;
+ Object i0070, i0071, i0072, i0073, i0074, i0075, i0076, i0077, i0078, i0079;
+ Object i0080, i0081, i0082, i0083, i0084, i0085, i0086, i0087, i0088, i0089;
+ Object i0090, i0091, i0092, i0093, i0094, i0095, i0096, i0097, i0098, i0099;
+
+ Object i0100, i0101, i0102, i0103, i0104, i0105, i0106, i0107, i0108, i0109;
+ Object i0110, i0111, i0112, i0113, i0114, i0115, i0116, i0117, i0118, i0119;
+ Object i0120, i0121, i0122, i0123, i0124, i0125, i0126, i0127, i0128, i0129;
+ Object i0130, i0131, i0132, i0133, i0134, i0135, i0136, i0137, i0138, i0139;
+ Object i0140, i0141, i0142, i0143, i0144, i0145, i0146, i0147, i0148, i0149;
+ Object i0150, i0151, i0152, i0153, i0154, i0155, i0156, i0157, i0158, i0159;
+ Object i0160, i0161, i0162, i0163, i0164, i0165, i0166, i0167, i0168, i0169;
+ Object i0170, i0171, i0172, i0173, i0174, i0175, i0176, i0177, i0178, i0179;
+ Object i0180, i0181, i0182, i0183, i0184, i0185, i0186, i0187, i0188, i0189;
+ Object i0190, i0191, i0192, i0193, i0194, i0195, i0196, i0197, i0198, i0199;
+
+ Object i0200, i0201, i0202, i0203, i0204, i0205, i0206, i0207, i0208, i0209;
+ Object i0210, i0211, i0212, i0213, i0214, i0215, i0216, i0217, i0218, i0219;
+ Object i0220, i0221, i0222, i0223, i0224, i0225, i0226, i0227, i0228, i0229;
+ Object i0230, i0231, i0232, i0233, i0234, i0235, i0236, i0237, i0238, i0239;
+ Object i0240, i0241, i0242, i0243, i0244, i0245, i0246, i0247, i0248, i0249;
+ Object i0250, i0251, i0252, i0253, i0254, i0255, i0256, i0257, i0258, i0259;
+ Object i0260, i0261, i0262, i0263, i0264, i0265, i0266, i0267, i0268, i0269;
+ Object i0270, i0271, i0272, i0273, i0274, i0275, i0276, i0277, i0278, i0279;
+ Object i0280, i0281, i0282, i0283, i0284, i0285, i0286, i0287, i0288, i0289;
+ Object i0290, i0291, i0292, i0293, i0294, i0295, i0296, i0297, i0298, i0299;
+
+ Object i0300, i0301, i0302, i0303, i0304, i0305, i0306, i0307, i0308, i0309;
+ Object i0310, i0311, i0312, i0313, i0314, i0315, i0316, i0317, i0318, i0319;
+ Object i0320, i0321, i0322, i0323, i0324, i0325, i0326, i0327, i0328, i0329;
+ Object i0330, i0331, i0332, i0333, i0334, i0335, i0336, i0337, i0338, i0339;
+ Object i0340, i0341, i0342, i0343, i0344, i0345, i0346, i0347, i0348, i0349;
+ Object i0350, i0351, i0352, i0353, i0354, i0355, i0356, i0357, i0358, i0359;
+ Object i0360, i0361, i0362, i0363, i0364, i0365, i0366, i0367, i0368, i0369;
+ Object i0370, i0371, i0372, i0373, i0374, i0375, i0376, i0377, i0378, i0379;
+ Object i0380, i0381, i0382, i0383, i0384, i0385, i0386, i0387, i0388, i0389;
+ Object i0390, i0391, i0392, i0393, i0394, i0395, i0396, i0397, i0398, i0399;
+
+ Object i0400, i0401, i0402, i0403, i0404, i0405, i0406, i0407, i0408, i0409;
+ Object i0410, i0411, i0412, i0413, i0414, i0415, i0416, i0417, i0418, i0419;
+ Object i0420, i0421, i0422, i0423, i0424, i0425, i0426, i0427, i0428, i0429;
+ Object i0430, i0431, i0432, i0433, i0434, i0435, i0436, i0437, i0438, i0439;
+ Object i0440, i0441, i0442, i0443, i0444, i0445, i0446, i0447, i0448, i0449;
+ Object i0450, i0451, i0452, i0453, i0454, i0455, i0456, i0457, i0458, i0459;
+ Object i0460, i0461, i0462, i0463, i0464, i0465, i0466, i0467, i0468, i0469;
+ Object i0470, i0471, i0472, i0473, i0474, i0475, i0476, i0477, i0478, i0479;
+ Object i0480, i0481, i0482, i0483, i0484, i0485, i0486, i0487, i0488, i0489;
+ Object i0490, i0491, i0492, i0493, i0494, i0495, i0496, i0497, i0498, i0499;
+
+ Object i0500, i0501, i0502, i0503, i0504, i0505, i0506, i0507, i0508, i0509;
+ Object i0510, i0511, i0512, i0513, i0514, i0515, i0516, i0517, i0518, i0519;
+ Object i0520, i0521, i0522, i0523, i0524, i0525, i0526, i0527, i0528, i0529;
+ Object i0530, i0531, i0532, i0533, i0534, i0535, i0536, i0537, i0538, i0539;
+ Object i0540, i0541, i0542, i0543, i0544, i0545, i0546, i0547, i0548, i0549;
+ Object i0550, i0551, i0552, i0553, i0554, i0555, i0556, i0557, i0558, i0559;
+ Object i0560, i0561, i0562, i0563, i0564, i0565, i0566, i0567, i0568, i0569;
+ Object i0570, i0571, i0572, i0573, i0574, i0575, i0576, i0577, i0578, i0579;
+ Object i0580, i0581, i0582, i0583, i0584, i0585, i0586, i0587, i0588, i0589;
+ Object i0590, i0591, i0592, i0593, i0594, i0595, i0596, i0597, i0598, i0599;
+
+ Object i0600, i0601, i0602, i0603, i0604, i0605, i0606, i0607, i0608, i0609;
+ Object i0610, i0611, i0612, i0613, i0614, i0615, i0616, i0617, i0618, i0619;
+ Object i0620, i0621, i0622, i0623, i0624, i0625, i0626, i0627, i0628, i0629;
+ Object i0630, i0631, i0632, i0633, i0634, i0635, i0636, i0637, i0638, i0639;
+ Object i0640, i0641, i0642, i0643, i0644, i0645, i0646, i0647, i0648, i0649;
+ Object i0650, i0651, i0652, i0653, i0654, i0655, i0656, i0657, i0658, i0659;
+ Object i0660, i0661, i0662, i0663, i0664, i0665, i0666, i0667, i0668, i0669;
+ Object i0670, i0671, i0672, i0673, i0674, i0675, i0676, i0677, i0678, i0679;
+ Object i0680, i0681, i0682, i0683, i0684, i0685, i0686, i0687, i0688, i0689;
+ Object i0690, i0691, i0692, i0693, i0694, i0695, i0696, i0697, i0698, i0699;
+
+ Object i0700, i0701, i0702, i0703, i0704, i0705, i0706, i0707, i0708, i0709;
+ Object i0710, i0711, i0712, i0713, i0714, i0715, i0716, i0717, i0718, i0719;
+ Object i0720, i0721, i0722, i0723, i0724, i0725, i0726, i0727, i0728, i0729;
+ Object i0730, i0731, i0732, i0733, i0734, i0735, i0736, i0737, i0738, i0739;
+ Object i0740, i0741, i0742, i0743, i0744, i0745, i0746, i0747, i0748, i0749;
+ Object i0750, i0751, i0752, i0753, i0754, i0755, i0756, i0757, i0758, i0759;
+ Object i0760, i0761, i0762, i0763, i0764, i0765, i0766, i0767, i0768, i0769;
+ Object i0770, i0771, i0772, i0773, i0774, i0775, i0776, i0777, i0778, i0779;
+ Object i0780, i0781, i0782, i0783, i0784, i0785, i0786, i0787, i0788, i0789;
+ Object i0790, i0791, i0792, i0793, i0794, i0795, i0796, i0797, i0798, i0799;
+
+ Object i0800, i0801, i0802, i0803, i0804, i0805, i0806, i0807, i0808, i0809;
+ Object i0810, i0811, i0812, i0813, i0814, i0815, i0816, i0817, i0818, i0819;
+ Object i0820, i0821, i0822, i0823, i0824, i0825, i0826, i0827, i0828, i0829;
+ Object i0830, i0831, i0832, i0833, i0834, i0835, i0836, i0837, i0838, i0839;
+ Object i0840, i0841, i0842, i0843, i0844, i0845, i0846, i0847, i0848, i0849;
+ Object i0850, i0851, i0852, i0853, i0854, i0855, i0856, i0857, i0858, i0859;
+ Object i0860, i0861, i0862, i0863, i0864, i0865, i0866, i0867, i0868, i0869;
+ Object i0870, i0871, i0872, i0873, i0874, i0875, i0876, i0877, i0878, i0879;
+ Object i0880, i0881, i0882, i0883, i0884, i0885, i0886, i0887, i0888, i0889;
+ Object i0890, i0891, i0892, i0893, i0894, i0895, i0896, i0897, i0898, i0899;
+
+ Object i0900, i0901, i0902, i0903, i0904, i0905, i0906, i0907, i0908, i0909;
+ Object i0910, i0911, i0912, i0913, i0914, i0915, i0916, i0917, i0918, i0919;
+ Object i0920, i0921, i0922, i0923, i0924, i0925, i0926, i0927, i0928, i0929;
+ Object i0930, i0931, i0932, i0933, i0934, i0935, i0936, i0937, i0938, i0939;
+ Object i0940, i0941, i0942, i0943, i0944, i0945, i0946, i0947, i0948, i0949;
+ Object i0950, i0951, i0952, i0953, i0954, i0955, i0956, i0957, i0958, i0959;
+ Object i0960, i0961, i0962, i0963, i0964, i0965, i0966, i0967, i0968, i0969;
+ Object i0970, i0971, i0972, i0973, i0974, i0975, i0976, i0977, i0978, i0979;
+ Object i0980, i0981, i0982, i0983, i0984, i0985, i0986, i0987, i0988, i0989;
+ Object i0990, i0991, i0992, i0993, i0994, i0995, i0996, i0997, i0998, i0999;
+
+ Object i1000, i1001, i1002, i1003, i1004, i1005, i1006, i1007, i1008, i1009;
+ Object i1010, i1011, i1012, i1013, i1014, i1015, i1016, i1017, i1018, i1019;
+ Object i1020, i1021, i1022, i1023, i1024, i1025, i1026, i1027, i1028, i1029;
+ Object i1030, i1031, i1032, i1033, i1034, i1035, i1036, i1037, i1038, i1039;
+ Object i1040, i1041, i1042, i1043, i1044, i1045, i1046, i1047, i1048, i1049;
+ Object i1050, i1051, i1052, i1053, i1054, i1055, i1056, i1057, i1058, i1059;
+ Object i1060, i1061, i1062, i1063, i1064, i1065, i1066, i1067, i1068, i1069;
+ Object i1070, i1071, i1072, i1073, i1074, i1075, i1076, i1077, i1078, i1079;
+ Object i1080, i1081, i1082, i1083, i1084, i1085, i1086, i1087, i1088, i1089;
+ Object i1090, i1091, i1092, i1093, i1094, i1095, i1096, i1097, i1098, i1099;
+
+ volatile Object volatileObjectField;
+ volatile int volatileIntField;
+ volatile long volatileWideField;
+
+ Object objectField;
+ int intField;
+ long wideField;
+
+ volatile Object putVolatileObjectField;
+ volatile int putVolatileIntField;
+ volatile long putVolatileWideField;
+
+ Object putObjectField;
+ int putIntField;
+ long putWideField;
+
+ static void check(NullPointerException npe, int firstLine) {
+ StackTraceElement[] trace = npe.getStackTrace();
+ checkElement(trace[0], "Main", "test", "Main.java", firstLine);
+ checkElement(trace[1], "Main", "main", "Main.java", 179);
+ }
+
+ static void checkElement(StackTraceElement element,
+ String declaringClass, String methodName,
+ String fileName, int lineNumber) {
+ assertEquals(declaringClass, element.getClassName());
+ assertEquals(methodName, element.getMethodName());
+ assertEquals(fileName, element.getFileName());
+ assertEquals(lineNumber, element.getLineNumber());
+ }
+
+ static void assertEquals(Object expected, Object actual) {
+ if (!expected.equals(actual)) {
+ String msg = "Expected \"" + expected + "\" but got \"" + actual + "\"";
+ throw new AssertionError(msg);
+ }
+ }
+
+ public static void main(String[] args) {
+ test();
+ }
+
+ public static void test() {
+ NullPointerException npe = null;
+ int thisLine = 184;
+
+ // We do each kind of test twice, to both test the fast path and the slow path
+ // of nterp.
+
+ try {
+ System.out.println($noinline$getNull().objectField);
+ } catch (NullPointerException e) {
+ npe = e;
+ }
+ check(npe, thisLine += 6);
+
+ try {
+ System.out.println($noinline$getNull().objectField);
+ } catch (NullPointerException e) {
+ npe = e;
+ }
+ check(npe, thisLine += 7);
+
+ try {
+ System.out.println($noinline$getNull().intField);
+ } catch (NullPointerException e) {
+ npe = e;
+ }
+ check(npe, thisLine += 7);
+
+ try {
+ System.out.println($noinline$getNull().intField);
+ } catch (NullPointerException e) {
+ npe = e;
+ }
+ check(npe, thisLine += 7);
+
+ try {
+ System.out.println($noinline$getNull().wideField);
+ } catch (NullPointerException e) {
+ npe = e;
+ }
+ check(npe, thisLine += 7);
+
+ try {
+ System.out.println($noinline$getNull().wideField);
+ } catch (NullPointerException e) {
+ npe = e;
+ }
+ check(npe, thisLine += 7);
+
+ try {
+ System.out.println($noinline$getNull().volatileObjectField);
+ } catch (NullPointerException e) {
+ npe = e;
+ }
+ check(npe, thisLine += 7);
+
+ try {
+ System.out.println($noinline$getNull().volatileObjectField);
+ } catch (NullPointerException e) {
+ npe = e;
+ }
+ check(npe, thisLine += 7);
+
+ try {
+ System.out.println($noinline$getNull().volatileIntField);
+ } catch (NullPointerException e) {
+ npe = e;
+ }
+ check(npe, thisLine += 7);
+
+ try {
+ System.out.println($noinline$getNull().volatileIntField);
+ } catch (NullPointerException e) {
+ npe = e;
+ }
+ check(npe, thisLine += 7);
+
+ try {
+ System.out.println($noinline$getNull().volatileWideField);
+ } catch (NullPointerException e) {
+ npe = e;
+ }
+ check(npe, thisLine += 7);
+
+ try {
+ System.out.println($noinline$getNull().volatileWideField);
+ } catch (NullPointerException e) {
+ npe = e;
+ }
+ check(npe, thisLine += 7);
+
+ try {
+ $noinline$getNull().putObjectField = null;
+ } catch (NullPointerException e) {
+ npe = e;
+ }
+ check(npe, thisLine += 7);
+
+ try {
+ $noinline$getNull().putObjectField = null;
+ } catch (NullPointerException e) {
+ npe = e;
+ }
+ check(npe, thisLine += 7);
+
+ try {
+ $noinline$getNull().putIntField = 42;
+ } catch (NullPointerException e) {
+ npe = e;
+ }
+ check(npe, thisLine += 7);
+
+ try {
+ $noinline$getNull().putIntField = 42;
+ } catch (NullPointerException e) {
+ npe = e;
+ }
+ check(npe, thisLine += 7);
+
+ try {
+ $noinline$getNull().putWideField = 42L;
+ } catch (NullPointerException e) {
+ npe = e;
+ }
+ check(npe, thisLine += 7);
+
+ try {
+ $noinline$getNull().putWideField = 42L;
+ } catch (NullPointerException e) {
+ npe = e;
+ }
+ check(npe, thisLine += 7);
+
+ try {
+ $noinline$getNull().putVolatileObjectField = null;
+ } catch (NullPointerException e) {
+ npe = e;
+ }
+ check(npe, thisLine += 7);
+
+ try {
+ $noinline$getNull().putVolatileObjectField = null;
+ } catch (NullPointerException e) {
+ npe = e;
+ }
+ check(npe, thisLine += 7);
+
+ try {
+ $noinline$getNull().putVolatileIntField = 42;
+ } catch (NullPointerException e) {
+ npe = e;
+ }
+ check(npe, thisLine += 7);
+
+ try {
+ $noinline$getNull().putVolatileIntField = 42;
+ } catch (NullPointerException e) {
+ npe = e;
+ }
+ check(npe, thisLine += 7);
+
+ try {
+ $noinline$getNull().putVolatileWideField = 42L;
+ } catch (NullPointerException e) {
+ npe = e;
+ }
+ check(npe, thisLine += 7);
+
+ try {
+ $noinline$getNull().putVolatileWideField = 42L;
+ } catch (NullPointerException e) {
+ npe = e;
+ }
+ check(npe, thisLine += 7);
+ }
+
+ public static Main $noinline$getNull() {
+ return null;
+ }
+}