arm nterp: Add support for heap poisoning.
Test: testrunner.py --target --jit --32
Change-Id: I6a5f1bc3d3d30feff7bb8d1528adebafdd24e20b
diff --git a/runtime/interpreter/mterp/armng/array.S b/runtime/interpreter/mterp/armng/array.S
index e685cbf..008081c 100644
--- a/runtime/interpreter/mterp/armng/array.S
+++ b/runtime/interpreter/mterp/armng/array.S
@@ -26,6 +26,7 @@
GOTO_OPCODE ip @ jump to next instruction
.elseif $is_object
$load r2, [r0, #$data_offset] @ w2<- vBB[vCC]
+ UNPOISON_HEAP_REF r2
TEST_IF_MARKING 2f
1:
GET_INST_OPCODE ip @ extract opcode from rINST
diff --git a/runtime/interpreter/mterp/armng/invoke.S b/runtime/interpreter/mterp/armng/invoke.S
index f12b18f..a4f76d8 100644
--- a/runtime/interpreter/mterp/armng/invoke.S
+++ b/runtime/interpreter/mterp/armng/invoke.S
@@ -87,6 +87,7 @@
GET_VREG r1, r1
// Note: if r1 is null, this will be handled by our SIGSEGV handler.
ldr r2, [r1, #MIRROR_OBJECT_CLASS_OFFSET]
+ UNPOISON_HEAP_REF r2
// Test the first two bits of the fetched ArtMethod:
// - If the first bit is set, this is a method on j.l.Object
// - If the second bit is set, this is a default method.
@@ -162,6 +163,7 @@
GET_VREG r1, r1
// Note: if r1 is null, this will be handled by our SIGSEGV handler.
ldr r0, [r1, #MIRROR_OBJECT_CLASS_OFFSET]
+ UNPOISON_HEAP_REF r0
add r0, r0, #MIRROR_CLASS_VTABLE_OFFSET_32
ldr r0, [r0, r2, lsl #2]
b $helper
diff --git a/runtime/interpreter/mterp/armng/main.S b/runtime/interpreter/mterp/armng/main.S
index 1e528d4..a6af738 100644
--- a/runtime/interpreter/mterp/armng/main.S
+++ b/runtime/interpreter/mterp/armng/main.S
@@ -1451,6 +1451,12 @@
GOTO_OPCODE ip
.endm
+.macro POISON_HEAP_REF_IF_OBJECT is_object, rRef
+ .if \is_object
+ POISON_HEAP_REF \rRef
+ .endif
+.endm
+
.macro WRITE_BARRIER_IF_OBJECT is_object, value, holder, label, tmp
.if \is_object
// In T32, we would use `SMART_CBZ \value, \label`
diff --git a/runtime/interpreter/mterp/armng/object.S b/runtime/interpreter/mterp/armng/object.S
index cde8cf9..9188592 100644
--- a/runtime/interpreter/mterp/armng/object.S
+++ b/runtime/interpreter/mterp/armng/object.S
@@ -8,6 +8,7 @@
cmp r0, #0
beq .L${opcode}_resume
ldr r2, [r0, #MIRROR_OBJECT_CLASS_OFFSET]
+ UNPOISON_HEAP_REF r2
// Fast path: do a comparison without read barrier.
cmp r1, r2
bne ${slow_path}
@@ -29,10 +30,12 @@
tst r3, #MIRROR_CLASS_IS_INTERFACE_FLAG
bne 2f
ldr r3, [r1, #MIRROR_CLASS_COMPONENT_TYPE_OFFSET]
+ UNPOISON_HEAP_REF r3
cmp r3, #0
bne 5f
1:
ldr r2, [r2, #MIRROR_CLASS_SUPER_CLASS_OFFSET]
+ UNPOISON_HEAP_REF r2
cmp r1, r2
beq .L${opcode}_resume
cmp r2, #0
@@ -49,10 +52,12 @@
5:
// Class in r1 is an array, r3 is the component type.
ldr r2, [r2, #MIRROR_CLASS_COMPONENT_TYPE_OFFSET]
+ UNPOISON_HEAP_REF r2
// Check if object is an array.
cmp r2, #0
beq 2b
ldr r4, [r3, #MIRROR_CLASS_SUPER_CLASS_OFFSET]
+ UNPOISON_HEAP_REF r4
cmp r4, #0
// If the super class of the component type is not null, go slow path.
bne 2b
@@ -75,6 +80,7 @@
cmp r0, #0
beq .L${opcode}_resume
ldr r2, [r0, #MIRROR_OBJECT_CLASS_OFFSET]
+ UNPOISON_HEAP_REF r2
// Fast path: do a comparison without read barrier.
cmp r1, r2
bne ${slow_path}
@@ -103,10 +109,12 @@
tst r3, #MIRROR_CLASS_IS_INTERFACE_FLAG
bne 5f
ldr r3, [r1, #MIRROR_CLASS_COMPONENT_TYPE_OFFSET]
+ UNPOISON_HEAP_REF r3
cmp r3, #0
bne 3f
1:
ldr r2, [r2, #MIRROR_CLASS_SUPER_CLASS_OFFSET]
+ UNPOISON_HEAP_REF r2
cmp r1, r2
beq .L${opcode}_set_one
cmp r2, #0
@@ -117,10 +125,12 @@
3:
// Class in r1 is an array, r3 is the component type.
ldr r2, [r2, #MIRROR_CLASS_COMPONENT_TYPE_OFFSET]
+ UNPOISON_HEAP_REF r2
// Check if object is an array.
cmp r2, #0
beq 2b
ldr r4, [r3, #MIRROR_CLASS_SUPER_CLASS_OFFSET]
+ UNPOISON_HEAP_REF r4
cmp r4, #0
bne 5f
ldrh r3, [r3, #MIRROR_CLASS_OBJECT_PRIMITIVE_TYPE_OFFSET]
@@ -167,6 +177,7 @@
SET_VREG_WIDE_BY_ADDR r0, r1, r2 // fp[A] <- value
.elseif $is_object
$load r0, [r3, r0]
+ UNPOISON_HEAP_REF r0
TEST_IF_MARKING .L${opcode}_read_barrier
.L${opcode}_resume_after_read_barrier:
SET_VREG_OBJECT r0, r2 // fp[A] <- value
@@ -209,6 +220,7 @@
$load r0, [r3, r0]
dmb ish
.if $is_object
+ UNPOISON_HEAP_REF r0
TEST_IF_MARKING .L${opcode}_read_barrier
SET_VREG_OBJECT r0, r2 // fp[A] <- value
.else
@@ -257,6 +269,7 @@
add r1, r1, r0
strd r2, r3, [r1]
.else
+ POISON_HEAP_REF_IF_OBJECT $is_object, r4
$store r4, [r1, r0]
WRITE_BARRIER_IF_OBJECT $is_object, r4, r1, .L${opcode}_skip_write_barrier, r0
.endif
@@ -301,6 +314,7 @@
cmp r1, #0
beq common_errNullObject
dmb ish
+ POISON_HEAP_REF_IF_OBJECT $is_object, r4
$store r4, [r1, r0]
dmb ish
WRITE_BARRIER_IF_OBJECT $is_object, r4, r1, .L${opcode}_slow_path_skip_write_barrier, r0
@@ -345,6 +359,7 @@
SET_VREG_WIDE_BY_ADDR r0, r1, r2 // fp[A] <- value
.elseif $is_object
$load r0, [r0, r1]
+ UNPOISON_HEAP_REF r0
// No need to check the marking register, we know it's not set here.
.L${opcode}_after_reference_load:
SET_VREG_OBJECT r0, r2 // fp[A] <- value
@@ -359,6 +374,7 @@
bl art_quick_read_barrier_mark_reg00
.if $is_object
ldr r0, [r0, r1]
+ UNPOISON_HEAP_REF r0
.L${opcode}_mark_after_load:
// Here, we know the marking register is set.
bl art_quick_read_barrier_mark_reg00
@@ -393,6 +409,7 @@
$load r0, [r0, r1]
dmb ish
.if $is_object
+ UNPOISON_HEAP_REF r0
TEST_IF_MARKING .L${opcode}_mark_after_load
SET_VREG_OBJECT r0, r2 // fp[A] <- value
.else
@@ -444,6 +461,7 @@
add r0, r0, r1
strd r2, r3, [r0]
.else
+ POISON_HEAP_REF_IF_OBJECT $is_object, r4
$store r4, [r0, r1]
WRITE_BARRIER_IF_OBJECT $is_object, r4, r0, .L${opcode}_skip_write_barrier, r1
.endif
@@ -487,6 +505,7 @@
dmb ish
.else
dmb ish
+ POISON_HEAP_REF_IF_OBJECT $is_object r4
$store r4, [r0, r1]
dmb ish
WRITE_BARRIER_IF_OBJECT $is_object, r4, r0, .L${opcode}_slow_path_skip_write_barrier, r1
diff --git a/runtime/interpreter/mterp/nterp.cc b/runtime/interpreter/mterp/nterp.cc
index 6ccc5e9..cf7ff00 100644
--- a/runtime/interpreter/mterp/nterp.cc
+++ b/runtime/interpreter/mterp/nterp.cc
@@ -39,7 +39,6 @@
switch (kRuntimeISA) {
case InstructionSet::kArm:
case InstructionSet::kThumb2:
- return !kPoisonHeapReferences && kReserveMarkingRegister;
case InstructionSet::kArm64:
return kReserveMarkingRegister;
case InstructionSet::kRiscv64: