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;
+  }
+}