summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Jaeheon Yi <jaeheon@google.com> 2023-12-19 18:23:56 -0800
committer Treehugger Robot <android-test-infra-autosubmit@system.gserviceaccount.com> 2024-01-25 22:23:26 +0000
commit360b1d08e4eaca3e15255265ab534844f2208d61 (patch)
tree248540b99685f61e07be4fc9d8108145d3270fdc
parent6f30991b16d1dcd386b6073a41a314a0120c7f48 (diff)
riscv64: new-instance, check-cast, instance-of, new-array
(1) setup lunch aosp_riscv64-trunk-userdebug export ART_TEST_SSH_USER=ubuntu export ART_TEST_SSH_HOST=localhost export ART_TEST_SSH_PORT=10001 export ART_TEST_ON_VM=true . art/tools/buildbot-utils.sh art/tools/buildbot-build.sh --target # Create, boot and configure the VM. art/tools/buildbot-vm.sh create art/tools/buildbot-vm.sh boot art/tools/buildbot-vm.sh setup-ssh # password: 'ubuntu' art/tools/buildbot-cleanup-device.sh art/tools/buildbot-setup-device.sh art/tools/buildbot-sync.sh (2) test art/test.py --target -r --no-prebuild --ndebug --64 -j 12 --cdex-none --interpreter Test: Run these opcodes against all interpreter tests on a Linux RISC-V VM. Test: Cuttlefish boot Bug: 283082047 Change-Id: I460dde59fe6e9ecdb33bd74186d01d5890da222c
-rw-r--r--runtime/arch/riscv64/quick_entrypoints_riscv64.S4
-rw-r--r--runtime/interpreter/mterp/riscv64/array.S33
-rw-r--r--runtime/interpreter/mterp/riscv64/main.S1
-rw-r--r--runtime/interpreter/mterp/riscv64/object.S262
-rw-r--r--runtime/nterp_helpers.cc4
5 files changed, 278 insertions, 26 deletions
diff --git a/runtime/arch/riscv64/quick_entrypoints_riscv64.S b/runtime/arch/riscv64/quick_entrypoints_riscv64.S
index bf00278a26..141974e14a 100644
--- a/runtime/arch/riscv64/quick_entrypoints_riscv64.S
+++ b/runtime/arch/riscv64/quick_entrypoints_riscv64.S
@@ -1836,9 +1836,9 @@ END \name
lwu \temp0, MIRROR_CLASS_OBJECT_PRIMITIVE_TYPE_OFFSET(\temp0)
srli \temp0, \temp0, PRIMITIVE_TYPE_SIZE_SHIFT_SHIFT // Component size shift is in high 16
// bits.
- // xCount is holding a 32 bit value,
+ zext.w \temp1, \count // From \count we use a 32 bit value,
// it can not overflow.
- sll \temp1, \count, \temp0 // Calculate data size
+ sll \temp1, \temp1, \temp0 // Calculate data size
// Add array data offset and alignment.
addi \temp1, \temp1, (MIRROR_INT_ARRAY_DATA_OFFSET + OBJECT_ALIGNMENT_MASK)
#if MIRROR_LONG_ARRAY_DATA_OFFSET != MIRROR_INT_ARRAY_DATA_OFFSET + 4
diff --git a/runtime/interpreter/mterp/riscv64/array.S b/runtime/interpreter/mterp/riscv64/array.S
index f4d92f1c8b..769747efa9 100644
--- a/runtime/interpreter/mterp/riscv64/array.S
+++ b/runtime/interpreter/mterp/riscv64/array.S
@@ -20,7 +20,38 @@
// Format 22c: B|A|23 CCCC
// Construct a new array of the indicated type and size. The type must be an array type.
%def op_new_array():
- unimp
+ EXPORT_PC
+ srliw s8, xINST, 8 // s8 := B|A
+ srliw s7, xINST, 12 // s7 := B
+ andi s8, s8, 0xF // s8 := A
+ FETCH_FROM_THREAD_CACHE /*resolved klass*/a0, .L${opcode}_miss, t0, t1
+ TEST_IF_MARKING t0, .L${opcode}_mark
+.L${opcode}_resume:
+
+% get_vreg("a1", "s7") # a1 := fp[B] length
+ ld t0, THREAD_ALLOC_ARRAY_ENTRYPOINT_OFFSET(xSELF)
+ jalr t0 // args a0 (klass), a1 (length)
+ // return a0 := new-array
+ fence w, w // constructor fence; main.S has details
+
+ SET_VREG_OBJECT a0, s8, z0=t0 // refs[A] := new-array
+ FETCH_ADVANCE_INST 2
+ GET_INST_OPCODE t0
+ GOTO_OPCODE t0
+
+.L${opcode}_mark:
+ call art_quick_read_barrier_mark_reg10 // a0, klass
+ j .L${opcode}_resume
+
+.L${opcode}_miss:
+ EXPORT_PC
+ mv a0, xSELF
+ ld a1, (sp) // caller ArtMethod*
+ mv a2, xPC
+ call nterp_get_class
+ j .L${opcode}_resume
+
+
// filled-new-array {vC, vD, vE, vF, vG}, type@BBBB
diff --git a/runtime/interpreter/mterp/riscv64/main.S b/runtime/interpreter/mterp/riscv64/main.S
index b799380a04..2490716f9a 100644
--- a/runtime/interpreter/mterp/riscv64/main.S
+++ b/runtime/interpreter/mterp/riscv64/main.S
@@ -626,6 +626,7 @@ NAME_END nterp_helper
EndExecuteNterpImpl:
// Entrypoints into runtime.
+NTERP_TRAMPOLINE nterp_allocate_object, NterpAllocateObject
NTERP_TRAMPOLINE nterp_filled_new_array, NterpFilledNewArray
NTERP_TRAMPOLINE nterp_filled_new_array_range, NterpFilledNewArrayRange
NTERP_TRAMPOLINE nterp_get_class, NterpGetClass
diff --git a/runtime/interpreter/mterp/riscv64/object.S b/runtime/interpreter/mterp/riscv64/object.S
index 7c8e10a6df..43bb31f1e9 100644
--- a/runtime/interpreter/mterp/riscv64/object.S
+++ b/runtime/interpreter/mterp/riscv64/object.S
@@ -1,17 +1,233 @@
+// check-cast vAA, type@BBBB
+// Format 21c: AA|1f BBBB
+// Throw a ClassCastException if the reference in the given register cannot be cast to the indicated
+// type.
%def op_check_cast():
- unimp
+ FETCH_FROM_THREAD_CACHE /*expected klass*/a1, .L${opcode}_miss, t0, t1
+.L${opcode}_miss_resume:
+
+ srliw t0, xINST, 8 // t0 := AA
+% get_vreg("a0", "t0", is_unsigned=True) # a0 := fp[AA], zext
+ beqz a0, .L${opcode}_next // null
+ lwu a2, MIRROR_OBJECT_CLASS_OFFSET(a0) // a2 := actual klass
+ UNPOISON_HEAP_REF a2
+ // Fast path: compare without read barrier.
+ bne a1, a2, .L${opcode}_slow
+
+.L${opcode}_next:
+ FETCH_ADVANCE_INST 2
+ GET_INST_OPCODE t0
+ GOTO_OPCODE t0
+
+.L${opcode}_miss:
+ EXPORT_PC
+ mv a0, xSELF
+ ld a1, (sp) // caller ArtMethod*
+ mv a2, xPC
+ call nterp_get_class
+ mv a1, a0
+ j .L${opcode}_miss_resume
-%def op_check_cast_slow_path():
- unimp
+.L${opcode}_slow:
+ // A0 and A1 in position for quick call.
+% slow_path = add_slow_path(op_check_cast_slow_path, "t0", "t1", "t2")
+ tail $slow_path // slow offset exceeds branch imm
+ // args a0, a1, a2
+
+
+// Checks cases for (1) interface, (2) array, and (3) super classes.
+// Hardcoded: a0 (obj), a1 (expected klass), a2 (actual klass)
+//
+// Note. We don't do read barriers for simplicity. However, this means that fetched objects may be a
+// from-space reference. That's OK as we only fetch constant information from the references. This
+// also means that some of the comparisons below may lead to false negative due to stale data, so
+// all negative cases must pass through the runtime, via potential read barrier.
+%def op_check_cast_slow_path(z0, z1, z2):
+ // Interface check: cut to runtime.
+ lwu $z0, MIRROR_CLASS_ACCESS_FLAGS_OFFSET(a1)
+ BRANCH_IF_BIT_SET $z0, $z0, MIRROR_CLASS_IS_INTERFACE_FLAG_BIT, .L${opcode}_runtime
+
+ // Array check handled below.
+ lwu $z0, MIRROR_CLASS_COMPONENT_TYPE_OFFSET(a1)
+ // Defer z0 unpoison to array path.
+ bnez $z0, .L${opcode}_array
+
+ // Super check: find expected class, else cut to runtime.
+.L${opcode}_super:
+ lwu a2, MIRROR_CLASS_SUPER_CLASS_OFFSET(a2)
+ UNPOISON_HEAP_REF a2
+ beq a2, a1, .L${opcode}_slow_next
+ bnez a2, .L${opcode}_super
+
+.L${opcode}_runtime:
+ TEST_IF_MARKING $z0, .L${opcode}_mark
+.L${opcode}_mark_resume:
+ EXPORT_PC
+ call art_quick_check_instance_of // args a0 (obj), a1 (expected klass)
+
+ // Advancement logic replicated here for branch distance.
+.L${opcode}_slow_next:
+ FETCH_ADVANCE_INST 2
+ GET_INST_OPCODE $z0
+ GOTO_OPCODE $z0
+.L${opcode}_mark:
+ call art_quick_read_barrier_mark_reg11 // a1, expected klass
+ j .L${opcode}_mark_resume
+
+.L${opcode}_array:
+ UNPOISON_HEAP_REF $z0 // z0 = expected.component
+ lwu $z1, MIRROR_CLASS_COMPONENT_TYPE_OFFSET(a2) // z1 := actual.component
+ beqz $z1, .L${opcode}_runtime // null: actual not an array
+ UNPOISON_HEAP_REF $z1
+ lwu $z2, MIRROR_CLASS_SUPER_CLASS_OFFSET($z0) // z2 := expected.component.super
+ // z2 can skip unpoison for null check
+ bnez $z2, .L${opcode}_runtime // super type exists
+ // expected.component.super is null: expected is either Object[] or primitive array.
+ lhu $z2, MIRROR_CLASS_OBJECT_PRIMITIVE_TYPE_OFFSET($z0) // z2 := expected.component.primitive
+ bnez $z2, .L${opcode}_runtime // expected's component is primitive
+ lwu $z2, MIRROR_CLASS_OBJECT_PRIMITIVE_TYPE_OFFSET($z1) // z2 := actual.component.primitive
+ bnez $z2, .L${opcode}_runtime // actual's component is primitive
+ // Here, z0 is Object, and z1 is a subclass of Object.
+ j .L${opcode}_slow_next
+
+
+// instance-of vA, vB, type@CCCC
+// Format 22c: B|A|20 CCCC
+// vA := 1 if vB instance-of CCCC, else 0
+// Store in the given destination register 1 if the indicated reference is an instance of the given
+// type, or 0 if not.
%def op_instance_of():
- unimp
+ srliw s7, xINST, 8 // s7 := B|A
+ srliw s8, xINST, 12 // s8 := B
+ andi s7, s7, 0xF // s7 := A, used in slow path
+ FETCH_FROM_THREAD_CACHE /*expected klass*/ a1, .L${opcode}_miss, t0, t1
+.L${opcode}_miss_resume:
+
+% get_vreg("a0", "s8", is_unsigned=True) # a0 := fp[B], zext
+ beqz a0, .L${opcode}_next // a0 = null = dst value "false"
+ lwu a2, MIRROR_OBJECT_CLASS_OFFSET(a0) // a2 := actual klass
+ UNPOISON_HEAP_REF a2
+ // Fast path: compare without read barrier.
+ bne a1, a2, .L${opcode}_slow
+
+ li a0, 1 // dst value "true"
+
+.L${opcode}_next:
+% set_vreg("a0", "s7", z0="t1") # fp[A] := a0
+ FETCH_ADVANCE_INST 2
+ GET_INST_OPCODE t0
+ GOTO_OPCODE t0
-%def op_instance_of_slow_path():
- unimp
+.L${opcode}_miss:
+ EXPORT_PC
+ mv a0, xSELF
+ ld a1, (sp) // caller ArtMethod*
+ mv a2, xPC
+ call nterp_get_class
+ mv a1, a0
+ j .L${opcode}_miss_resume
+.L${opcode}_slow:
+ // A0 and A1 in position for quick call.
+% slow_path = add_slow_path(op_instance_of_slow_path, "s7", "t0", "t1", "t2")
+ tail $slow_path // slow offset exceeds branch imm
+ // args a0, a1, a2
+
+
+// Checks cases for (1) interface, (2) array, and (3) super classes.
+// Hardcoded: a0 (obj), a1 (expected klass), a2 (actual klass)
+//
+// Npte. If marking, don't bother with read barrier calls - cut to runtime. This arrangement allows
+// the (non marking) super class fast path's negative case to skip the read barrier and runtime
+// call, and correctly diagnose the situation with fp[A] := 0.
+%def op_instance_of_slow_path(vA, z0, z1, z2):
+ TEST_IF_MARKING $z0, .L${opcode}_runtime_with_read_barrier
+
+ // Interface check: cut to runtime.
+ lwu $z0, MIRROR_CLASS_ACCESS_FLAGS_OFFSET(a1)
+ BRANCH_IF_BIT_SET $z0, $z0, MIRROR_CLASS_IS_INTERFACE_FLAG_BIT, .L${opcode}_runtime
+
+ // Array check handled below.
+ lwu $z0, MIRROR_CLASS_COMPONENT_TYPE_OFFSET(a1)
+ // Defer z0 unpoison to array path.
+ bnez $z0, .L${opcode}_array
+
+ // Super check: find klass up the hierarchy.
+.L${opcode}_super:
+ lwu a2, MIRROR_CLASS_SUPER_CLASS_OFFSET(a2)
+ UNPOISON_HEAP_REF a2
+ beq a2, a1, .L${opcode}_super_exit
+ bnez a2, .L${opcode}_super
+.L${opcode}_super_exit:
+ snez a0, a2 // a0 := 1 if (a1 = a2 != null), else 0 (because a2 = null)
+
+.L${opcode}_slow_next:
+% set_vreg("a0", vA, z0=z0) # fp[A] := a0
+ FETCH_ADVANCE_INST 2
+ GET_INST_OPCODE $z0
+ GOTO_OPCODE $z0
+
+.L${opcode}_runtime_with_read_barrier:
+ call art_quick_read_barrier_mark_reg11 // a1, expected klass
+.L${opcode}_runtime:
+ EXPORT_PC
+ call artInstanceOfFromCode // args a0 (obj), a1 (expected klass)
+ // return a0: 1 if true, else 0
+ j .L${opcode}_slow_next
+
+.L${opcode}_array:
+ UNPOISON_HEAP_REF $z0 // z0 = expected.component
+ lwu $z1, MIRROR_CLASS_SUPER_CLASS_OFFSET($z0) // z1 := expected.component.super
+ // z1 can skip unpoison for null check
+ bnez $z1, .L${opcode}_runtime // super type exists
+ // Here, expected.component.super is null: expected is either Object[] or primitive array.
+ lwu a0, MIRROR_CLASS_COMPONENT_TYPE_OFFSET(a2) // a0 := actual.component
+ beqz a0, .L${opcode}_slow_next // actual not an array, a0 = null = dst value "false"
+ UNPOISON_HEAP_REF a0
+ lhu $z1, MIRROR_CLASS_OBJECT_PRIMITIVE_TYPE_OFFSET($z0) // z1 := expected.component.primitive
+ lhu $z2, MIRROR_CLASS_OBJECT_PRIMITIVE_TYPE_OFFSET(a0) // z2 := actual.component.primitive
+ or a0, $z1, $z2 // a0 := 0 if z1 = z2 = 0, else non-zero (Primitive::Type enum)
+ seqz a0, a0 // a0 := 1 if both are class types, else 0
+ // Here, when a0 = 1, expected.component is Object, and actual.component is a subclass of Object.
+ j .L${opcode}_slow_next
+
+
+// new-instance vAA, type@BBBB
+// Format 21c: AA|22 BBBB
+// Construct a new instance of the indicated type, storing a reference to it in the destination. The
+// type must refer to a non-array class.
%def op_new_instance():
- unimp
+ EXPORT_PC
+ srliw s7, xINST, 8 // s7 := AA
+ FETCH_FROM_THREAD_CACHE /*resolved klass*/a0, .L${opcode}_miss, t0, t1
+ TEST_IF_MARKING t0, .L${opcode}_mark
+.L${opcode}_mark_resume:
+
+ ld t0, THREAD_ALLOC_OBJECT_ENTRYPOINT_OFFSET(xSELF)
+ jalr t0 // arg a0 (klass)
+ // return a0 := new-obj
+ fence w, w // constructor fence; main.S has details
+
+.L${opcode}_miss_resume:
+ SET_VREG_OBJECT a0, s7, z0=t0 // refs[AA] := new-obj
+ FETCH_ADVANCE_INST 2
+ GET_INST_OPCODE t0
+ GOTO_OPCODE t0
+
+.L${opcode}_mark:
+ call art_quick_read_barrier_mark_reg10 // a0, klass
+ j .L${opcode}_mark_resume
+
+.L${opcode}_miss:
+ EXPORT_PC
+ mv a0, xSELF
+ ld a1, (sp) // caller ArtMethod*
+ mv a2, xPC
+ call nterp_allocate_object
+ // return a0 := new-obj, plus cache entry is updated with the resolved klass
+ j .L${opcode}_miss_resume
+
// *** iget ***
@@ -51,15 +267,15 @@
// Format 22c: B|A|52 CCCC
// vA := vB.field
%def op_iget(width=32, zext=False):
- srliw s7, xINST, 12 // s7 := B
srliw s8, xINST, 8
+ srliw s7, xINST, 12 // s7 := B
andi s8, s8, 0xF // s8 := A
// Fast path: NterpGetInstanceFieldOffset's byte offset from thread-local cache.
FETCH_FROM_THREAD_CACHE /*field_offset*/a0, .L${opcode}_slow, t1, t2
.L${opcode}_slow_resume:
- GET_VREG_OBJECT t0, s7 // t0 := holder
+% get_vreg("t0", "s7", is_unsigned=True) # t0 := holder
beqz t0, .L${opcode}_null
add t0, a0, t0 // t0 := field addr
% load(dst="t1", src="t0", width=width, zext=zext)
@@ -87,7 +303,7 @@
%def op_iget_volatile(width, zext, holder, dst, z0, z1):
- GET_VREG_OBJECT $z0, $holder // z0 := holder
+% get_vreg(z0, holder, is_unsigned=True) # z0 := holder
beqz $z0, .L${opcode}_volatile_null
sub $z0, $z0, a0 // z0 := field addr (holder - (-offset))
// Atomic load: "fence rw,rw ; LOAD ; fence r,rw"
@@ -113,15 +329,15 @@
// iget-object vA, vB, field@CCCC
// Format 22c: B|A|54 CCCC
%def op_iget_object():
- srliw s7, xINST, 12 // s7 := B
srliw s8, xINST, 8
+ srliw s7, xINST, 12 // s7 := B
andi s8, s8, 0xF // s8 := A
// Fast path: NterpGetInstanceFieldOffset's byte offset from thread-local cache.
FETCH_FROM_THREAD_CACHE /*field_offset*/a0, .L${opcode}_slow, t1, t2
.L${opcode}_slow_resume:
- GET_VREG_OBJECT t0, s7 // t0 := holder
+% get_vreg("t0", "s7", is_unsigned=True) # t0 := holder
beqz t0, .L${opcode}_null
add t0, a0, t0 // t0 := field addr
lwu a0, (t0) // a0 := object
@@ -159,7 +375,7 @@
tail .L${opcode}_slow_resume // resume offset exceeds branch imm
.L${opcode}_volatile:
- GET_VREG_OBJECT $z0, $holder // z0 := holder
+% get_vreg(z0, holder, is_unsigned=True) # z0 := holder
beqz $z0, .L${opcode}_volatile_null
sub $z0, $z0, a0 // z0 := field addr (holder - (-offset))
// Atomic load: "fence rw,rw ; LOAD ; fence r,rw"
@@ -213,8 +429,8 @@
// Format 22c: B|A|59 CCCC
// vB.field := vA
%def op_iput(width=32):
- srliw s7, xINST, 12 // s7 := B
srliw s8, xINST, 8
+ srliw s7, xINST, 12 // s7 := B
andi s8, s8, 0xF // s8 := A
% get_vreg("s8", "s8", width=width)
// s8 := value, held across slow path call
@@ -223,7 +439,7 @@
FETCH_FROM_THREAD_CACHE /*resolved_field*/a0, .L${opcode}_slow, t0, t1
.L${opcode}_slow_resume:
- GET_VREG_OBJECT t0, s7 // t0 := holder
+% get_vreg("t0", "s7", is_unsigned=True) # t0 := holder
beqz t0, .L${opcode}_null
add t0, a0, t0 // t0 := field addr
FETCH_ADVANCE_INST 2
@@ -249,7 +465,7 @@
%def op_iput_volatile(width, holder, value, z0, z1):
- GET_VREG_OBJECT $z0, $holder // z0 := holder
+% get_vreg(z0, holder, is_unsigned=True) # z0 := holder
beqz $z0, .L${opcode}_volatile_null
sub $z0, $z0, a0 // z0 := field addr (holder - (-offset))
// Ensure the volatile store is released.
@@ -286,16 +502,16 @@
// iput-object vA, vB, field@CCCC
// Format 22c: B|A|5b CCCC
%def op_iput_object():
- srliw s7, xINST, 12 // s7 := B
srliw s8, xINST, 8
+ srliw s7, xINST, 12 // s7 := B
andi s8, s8, 0xF // s8 := A
- GET_VREG_OBJECT s9, s8 // s9 := reference
+% get_vreg("s9", "s8", is_unsigned=True) # s9 := reference
// Fast path: NterpGetInstanceFieldOffset's byte offset from thread-local cache.
FETCH_FROM_THREAD_CACHE /*resolved_field*/a0, .L${opcode}_slow, t0, t1
.L${opcode}_slow_resume: // s9 := reference (slow path only)
- GET_VREG_OBJECT t0, s7 // t0 := holder
+% get_vreg("t0", "s7", is_unsigned=True) # t0 := holder
beqz t0, .L${opcode}_null
add t1, a0, t0 // t1 := field addr
POISON_HEAP_REF s9 // Poisoning maps null to null for the null check in write barrier.
@@ -323,14 +539,14 @@
call nterp_get_instance_field_offset // result a0 := field_offset
// Reload value, object may have moved.
- GET_VREG_OBJECT $value, $src // value := v[A]
+% get_vreg(value, src, is_unsigned=True) # value := fp[A] zext
// Test for volatile (negative value).
bltz a0, .L${opcode}_volatile
tail .L${opcode}_slow_resume // resume offset exceeds branch imm
.L${opcode}_volatile:
- GET_VREG_OBJECT $z0, $holder // z0 := holder
+% get_vreg(z0, holder, is_unsigned=True) # z0 := holder
beqz $z0, .L${opcode}_volatile_null
sub $z1, $z0, a0 // z1 := field addr (holder - (-offset))
// Ensure the volatile store is released.
@@ -647,7 +863,7 @@
// Format 21c: AA|69 BBBB
%def op_sput_object():
srliw s7, xINST, 8 // s7 := AA (live through slow path)
- GET_VREG_OBJECT s8, s7 // s8 := reference, replaced in slow path
+% get_vreg("s8", "s7", is_unsigned=True) # s8 := reference, replaced in slow path
// Fast path: NterpGetStaticField's resolved_field from thread-local cache.
// Stores cache value in a0 to match slow path's return from NterpGetStaticField.
@@ -690,7 +906,7 @@
call nterp_get_static_field // result a0 := resolved_field
// Reload value, it may have moved.
- GET_VREG_OBJECT $value, $src_vreg // value := v[AA]
+% get_vreg(value, src_vreg, is_unsigned=True) # value := fp[AA], zext
// Test for volatile bit
slli $z0, a0, 63
diff --git a/runtime/nterp_helpers.cc b/runtime/nterp_helpers.cc
index 328ef629c4..55e58c5d84 100644
--- a/runtime/nterp_helpers.cc
+++ b/runtime/nterp_helpers.cc
@@ -277,7 +277,11 @@ bool CanMethodUseNterp(ArtMethod* method, InstructionSet isa) {
case Instruction::CONST_CLASS:
case Instruction::MONITOR_ENTER:
case Instruction::MONITOR_EXIT:
+ case Instruction::CHECK_CAST:
+ case Instruction::INSTANCE_OF:
case Instruction::ARRAY_LENGTH:
+ case Instruction::NEW_INSTANCE:
+ case Instruction::NEW_ARRAY:
case Instruction::FILLED_NEW_ARRAY:
case Instruction::FILLED_NEW_ARRAY_RANGE:
case Instruction::FILL_ARRAY_DATA: