531 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			ArmAsm
		
	
	
	
			
		
		
	
	
			531 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			ArmAsm
		
	
	
	
| %def op_check_cast():
 | |
| %  slow_path = add_slow_path(op_check_cast_slow_path)
 | |
|    // Fast-path which gets the class from thread-local cache.
 | |
| %  fetch_from_thread_cache("r1", miss_label="2f")
 | |
| 1:
 | |
|    lsr     r2, rINST, #8               // r2<- A
 | |
|    GET_VREG r0, r2                     // r0<- vA (object)
 | |
|    cmp     r0, #0
 | |
|    beq     .L${opcode}_resume
 | |
|    ldr     r2, [r0, #MIRROR_OBJECT_CLASS_OFFSET]
 | |
|    // Fast path: do a comparison without read barrier.
 | |
|    cmp     r1, r2
 | |
|    bne     ${slow_path}
 | |
| .L${opcode}_resume:
 | |
|    FETCH_ADVANCE_INST 2
 | |
|    GET_INST_OPCODE ip
 | |
|    GOTO_OPCODE ip
 | |
| 2:
 | |
|    EXPORT_PC
 | |
|    mov     r0, rSELF
 | |
|    ldr     r1, [sp]
 | |
|    mov     r2, rPC
 | |
|    bl      nterp_get_class_or_allocate_object
 | |
|    mov     r1, r0
 | |
|    b       1b
 | |
| 
 | |
| %def op_check_cast_slow_path():
 | |
|    ldr     r3, [r1, #MIRROR_CLASS_ACCESS_FLAGS_OFFSET]
 | |
|    tst     r3, #MIRROR_CLASS_IS_INTERFACE_FLAG
 | |
|    bne     2f
 | |
|    ldr     r3, [r1, #MIRROR_CLASS_COMPONENT_TYPE_OFFSET]
 | |
|    cmp     r3, #0
 | |
|    bne     5f
 | |
| 1:
 | |
|    ldr     r2, [r2, #MIRROR_CLASS_SUPER_CLASS_OFFSET]
 | |
|    cmp     r1, r2
 | |
|    beq     .L${opcode}_resume
 | |
|    cmp     r2, #0
 | |
|    bne     1b
 | |
| 2:
 | |
|    TEST_IF_MARKING 4f
 | |
| 3:
 | |
|    EXPORT_PC
 | |
|    bl      art_quick_check_instance_of
 | |
|    b       .L${opcode}_resume
 | |
| 4:
 | |
|    bl      art_quick_read_barrier_mark_reg01
 | |
|    b       3b
 | |
| 5:
 | |
|    // Class in r1 is an array, r3 is the component type.
 | |
|    ldr     r2, [r2, #MIRROR_CLASS_COMPONENT_TYPE_OFFSET]
 | |
|    // Check if object is an array.
 | |
|    cmp     r2, #0
 | |
|    beq     2b
 | |
|    ldr     r4, [r3, #MIRROR_CLASS_SUPER_CLASS_OFFSET]
 | |
|    cmp     r4, #0
 | |
|    // If the super class of the component type is not null, go slow path.
 | |
|    bne     2b
 | |
|    ldrh    r3, [r3, #MIRROR_CLASS_OBJECT_PRIMITIVE_TYPE_OFFSET]
 | |
|    // Check if the object is a primitive array.
 | |
|    ldrh    r2, [r2, #MIRROR_CLASS_OBJECT_PRIMITIVE_TYPE_OFFSET]
 | |
|    orrs    r2, r3
 | |
|    beq     .L${opcode}_resume
 | |
|    // Go slow path for throwing the exception.
 | |
|    b 2b
 | |
| 
 | |
| %def op_instance_of():
 | |
| %  slow_path = add_slow_path(op_instance_of_slow_path)
 | |
|    /* instance-of vA, vB, class@CCCC */
 | |
|    // Fast-path which gets the class from thread-local cache.
 | |
| %  fetch_from_thread_cache("r1", miss_label="2f")
 | |
| 1:
 | |
|    lsr     r2, rINST, #12              // r2<- B
 | |
|    GET_VREG r0, r2                     // r0<- vB (object)
 | |
|    cmp     r0, #0
 | |
|    beq     .L${opcode}_resume
 | |
|    ldr     r2, [r0, #MIRROR_OBJECT_CLASS_OFFSET]
 | |
|    // Fast path: do a comparison without read barrier.
 | |
|    cmp     r1, r2
 | |
|    bne     ${slow_path}
 | |
| .L${opcode}_set_one:
 | |
|    mov     r0, #1
 | |
| .L${opcode}_resume:
 | |
|    ubfx    r1, rINST, #8, #4           // r1<- A
 | |
|    SET_VREG r0, r1
 | |
|    FETCH_ADVANCE_INST 2
 | |
|    GET_INST_OPCODE ip
 | |
|    GOTO_OPCODE ip
 | |
| 2:
 | |
|    EXPORT_PC
 | |
|    mov     r0, rSELF
 | |
|    ldr     r1, [sp]
 | |
|    mov     r2, rPC
 | |
|    bl      nterp_get_class_or_allocate_object
 | |
|    mov     r1, r0
 | |
|    b       1b
 | |
| 
 | |
| %def op_instance_of_slow_path():
 | |
|    // Go slow path if we are marking. Checking now allows
 | |
|    // not going to slow path if the super class hierarchy check fails.
 | |
|    TEST_IF_MARKING 4f
 | |
|    ldr     r3, [r1, #MIRROR_CLASS_ACCESS_FLAGS_OFFSET]
 | |
|    tst     r3, #MIRROR_CLASS_IS_INTERFACE_FLAG
 | |
|    bne     5f
 | |
|    ldr     r3, [r1, #MIRROR_CLASS_COMPONENT_TYPE_OFFSET]
 | |
|    cmp     r3, #0
 | |
|    bne     3f
 | |
| 1:
 | |
|    ldr     r2, [r2, #MIRROR_CLASS_SUPER_CLASS_OFFSET]
 | |
|    cmp     r1, r2
 | |
|    beq     .L${opcode}_set_one
 | |
|    cmp     r2, #0
 | |
|    bne     1b
 | |
| 2:
 | |
|    mov     r0, #0
 | |
|    b       .L${opcode}_resume
 | |
| 3:
 | |
|    // Class in r1 is an array, r3 is the component type.
 | |
|    ldr     r2, [r2, #MIRROR_CLASS_COMPONENT_TYPE_OFFSET]
 | |
|    // Check if object is an array.
 | |
|    cmp     r2, #0
 | |
|    beq     2b
 | |
|    ldr     r4, [r3, #MIRROR_CLASS_SUPER_CLASS_OFFSET]
 | |
|    cmp     r4, #0
 | |
|    bne     5f
 | |
|    ldrh    r3, [r3, #MIRROR_CLASS_OBJECT_PRIMITIVE_TYPE_OFFSET]
 | |
|    // Check if the object is a primitive array.
 | |
|    ldrh    r2, [r2, #MIRROR_CLASS_OBJECT_PRIMITIVE_TYPE_OFFSET]
 | |
|    orr     r0, r2, r3
 | |
|    clz     r0, r0
 | |
|    lsrs    r0, r0, #5
 | |
|    b       .L${opcode}_resume
 | |
| 4:
 | |
|    bl      art_quick_read_barrier_mark_reg01
 | |
| 5:
 | |
|    EXPORT_PC
 | |
|    bl      artInstanceOfFromCode
 | |
|    b       .L${opcode}_resume
 | |
| 
 | |
| %def op_iget_boolean():
 | |
| %  op_iget(load="ldrb", wide="0", is_object="0")
 | |
| 
 | |
| %def op_iget_byte():
 | |
| %  op_iget(load="ldrsb", wide="0", is_object="0")
 | |
| 
 | |
| %def op_iget_char():
 | |
| %  op_iget(load="ldrh", wide="0", is_object="0")
 | |
| 
 | |
| %def op_iget_short():
 | |
| %  op_iget(load="ldrsh", wide="0", is_object="0")
 | |
| 
 | |
| %def op_iget(load="ldr", wide="0", is_object="0"):
 | |
| %  slow_path = add_slow_path(op_iget_slow_path, load, wide, is_object)
 | |
|    // Fast-path which gets the field from thread-local cache.
 | |
| %  fetch_from_thread_cache("r0", miss_label=slow_path)
 | |
| .L${opcode}_resume:
 | |
|    lsr     r2, rINST, #12              // r2<- B
 | |
|    GET_VREG r3, r2                     // r3<- object we're operating on
 | |
|    ubfx    r2, rINST, #8, #4           // r2<- A
 | |
|    cmp     r3, #0
 | |
|    beq     common_errNullObject        // object was null
 | |
|    .if $wide
 | |
|    add     r3, r3, r0
 | |
|    ldrd    r0, r1, [r3]
 | |
|    CLEAR_SHADOW_PAIR r2, ip, lr
 | |
|    VREG_INDEX_TO_ADDR r2, r2
 | |
|    SET_VREG_WIDE_BY_ADDR r0, r1, r2    // fp[A] <- value
 | |
|    .elseif $is_object
 | |
|    $load   r0, [r3, r0]
 | |
|    TEST_IF_MARKING .L${opcode}_read_barrier
 | |
| .L${opcode}_resume_after_read_barrier:
 | |
|    SET_VREG_OBJECT r0, r2              // fp[A] <- value
 | |
|    .else
 | |
|    $load   r0, [r3, r0]
 | |
|    SET_VREG r0, r2                     // fp[A] <- value
 | |
|    .endif
 | |
|    FETCH_ADVANCE_INST 2
 | |
|    GET_INST_OPCODE ip
 | |
|    GOTO_OPCODE ip
 | |
|    .if $is_object
 | |
| .L${opcode}_read_barrier:
 | |
|    bl      art_quick_read_barrier_mark_reg00
 | |
|    b       .L${opcode}_resume_after_read_barrier
 | |
|    .endif
 | |
| 
 | |
| %def op_iget_slow_path(load, wide, is_object):
 | |
|    mov     r0, rSELF
 | |
|    ldr     r1, [sp]
 | |
|    mov     r2, rPC
 | |
|    mov     r3, #0
 | |
|    EXPORT_PC
 | |
|    bl      nterp_get_instance_field_offset
 | |
|    cmp     r0, #0
 | |
|    bge     .L${opcode}_resume
 | |
|    CLEAR_INSTANCE_VOLATILE_MARKER r0
 | |
|    lsr     r2, rINST, #12              // r2<- B
 | |
|    GET_VREG r3, r2                     // r3<- object we're operating on
 | |
|    ubfx    r2, rINST, #8, #4           // r2<- A
 | |
|    cmp     r3, #0
 | |
|    beq     common_errNullObject            // object was null
 | |
|    .if $wide
 | |
|    add     ip, r3, r0
 | |
|    ATOMIC_LOAD64 ip, r0, r1, r3, .L${opcode}_slow_path_atomic_load
 | |
|    dmb     ish
 | |
|    CLEAR_SHADOW_PAIR r2, ip, lr
 | |
|    VREG_INDEX_TO_ADDR r2, r2
 | |
|    SET_VREG_WIDE_BY_ADDR r0, r1, r2    // fp[A] <- value
 | |
|    .else
 | |
|    $load   r0, [r3, r0]
 | |
|    dmb     ish
 | |
|    .if $is_object
 | |
|    TEST_IF_MARKING .L${opcode}_read_barrier
 | |
|    SET_VREG_OBJECT r0, r2              // fp[A] <- value
 | |
|    .else
 | |
|    SET_VREG r0, r2                     // fp[A] <- value
 | |
|    .endif
 | |
|    .endif
 | |
|    FETCH_ADVANCE_INST 2
 | |
|    GET_INST_OPCODE ip
 | |
|    GOTO_OPCODE ip
 | |
| 
 | |
| %def op_iget_wide():
 | |
| %  op_iget(load="ldr", wide="1", is_object="0")
 | |
| 
 | |
| %def op_iget_object():
 | |
| %  op_iget(load="ldr", wide="0", is_object="1")
 | |
| 
 | |
| %def op_iput_boolean():
 | |
| %  op_iput(store="strb", wide="0", is_object="0")
 | |
| 
 | |
| %def op_iput_byte():
 | |
| %  op_iput(store="strb", wide="0", is_object="0")
 | |
| 
 | |
| %def op_iput_char():
 | |
| %  op_iput(store="strh", wide="0", is_object="0")
 | |
| 
 | |
| %def op_iput_short():
 | |
| %  op_iput(store="strh", wide="0", is_object="0")
 | |
| 
 | |
| %def op_iput(store="str", wide="0", is_object="0"):
 | |
| %  slow_path = add_slow_path(op_iput_slow_path, store, wide, is_object)
 | |
|    .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", miss_label=slow_path)
 | |
| .L${opcode}_resume:
 | |
|    lsr     r1, rINST, #12              // r1<- B
 | |
|    GET_VREG r1, r1                     // vB (object we're operating on)
 | |
|    cmp     r1, #0
 | |
|    beq     common_errNullObject
 | |
|    .if $wide
 | |
|    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
 | |
|    $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
 | |
|    GOTO_OPCODE ip
 | |
| 
 | |
| %def op_iput_slow_path(store, wide, is_object):
 | |
|    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
 | |
|    .if $is_object
 | |
|    // Reload the value as it may have moved.
 | |
|    ubfx    r4, rINST, #8, #4           // r4<- A
 | |
|    GET_VREG r4, r4                     // r4 <- v[A]
 | |
|    .endif
 | |
|    cmp     r0, #0
 | |
|    bge     .L${opcode}_resume
 | |
|    CLEAR_INSTANCE_VOLATILE_MARKER r0
 | |
|    .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
 | |
|    VREG_INDEX_TO_ADDR r1, r1
 | |
|    GET_VREG_WIDE_BY_ADDR r2, r3, r1
 | |
|    add     ip, r4, r0
 | |
|    dmb     ish
 | |
|    ATOMIC_STORE64 ip, r2, r3, r0, r1, .L${opcode}_slow_path_atomic_store
 | |
|    dmb     ish
 | |
|    .else
 | |
|    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  r4, [r1, r0]
 | |
|    dmb     ish
 | |
|    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
 | |
|    GOTO_OPCODE ip
 | |
| 
 | |
| %def op_iput_wide():
 | |
| %  op_iput(store="str", wide="1", is_object="0")
 | |
| 
 | |
| %def op_iput_object():
 | |
| %  op_iput(store="str", wide="0", is_object="1")
 | |
| 
 | |
| %def op_sget_boolean():
 | |
| %  op_sget(load="ldrb", wide="0", is_object="0")
 | |
| 
 | |
| %def op_sget_byte():
 | |
| %  op_sget(load="ldrsb", wide="0", is_object="0")
 | |
| 
 | |
| %def op_sget_char():
 | |
| %  op_sget(load="ldrh", wide="0", is_object="0")
 | |
| 
 | |
| %def op_sget_short():
 | |
| %  op_sget(load="ldrsh", wide="0", is_object="0")
 | |
| 
 | |
| %def op_sget(load="ldr", wide="0", is_object="0"):
 | |
| %  slow_path = add_slow_path(op_sget_slow_path, load, wide, is_object)
 | |
|    // Fast-path which gets the field from thread-local cache.
 | |
| %  fetch_from_thread_cache("r0", miss_label=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]
 | |
|    TEST_IF_MARKING .L${opcode}_read_barrier
 | |
| .L${opcode}_resume_after_read_barrier:
 | |
|    .if $wide
 | |
|    add     r0, r0, r1
 | |
|    ldrd    r0, r1, [r0]
 | |
|    CLEAR_SHADOW_PAIR r2, ip, lr
 | |
|    VREG_INDEX_TO_ADDR r2, r2
 | |
|    SET_VREG_WIDE_BY_ADDR r0, r1, r2    // fp[A] <- value
 | |
|    .elseif $is_object
 | |
|    $load   r0, [r0, r1]
 | |
|    // 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
 | |
|    .else
 | |
|    $load   r0, [r0, r1]
 | |
|    SET_VREG r0, r2                     // fp[A] <- value
 | |
|    .endif
 | |
|    FETCH_ADVANCE_INST 2
 | |
|    GET_INST_OPCODE ip
 | |
|    GOTO_OPCODE ip
 | |
| .L${opcode}_read_barrier:
 | |
|    bl      art_quick_read_barrier_mark_reg00
 | |
|    .if $is_object
 | |
|    ldr     r0, [r0, r1]
 | |
| .L${opcode}_mark_after_load:
 | |
|    // Here, we know the marking register is set.
 | |
|    bl      art_quick_read_barrier_mark_reg00
 | |
|    b       .L${opcode}_after_reference_load
 | |
|    .else
 | |
|    b       .L${opcode}_resume_after_read_barrier
 | |
|    .endif
 | |
| 
 | |
| %def op_sget_slow_path(load="ldr", wide="0", is_object="0"):
 | |
|    mov     r0, rSELF
 | |
|    ldr     r1, [sp]
 | |
|    mov     r2, rPC
 | |
|    mov     r3, #0
 | |
|    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]
 | |
|    TEST_IF_MARKING .L${opcode}_slow_path_read_barrier
 | |
| .L${opcode}_slow_path_resume_after_read_barrier:
 | |
|    .if $wide
 | |
|    add     ip, r0, r1
 | |
|    ATOMIC_LOAD64 ip, r0, r1, r3, .L${opcode}_slow_path_atomic_load
 | |
|    dmb     ish
 | |
|    CLEAR_SHADOW_PAIR r2, ip, lr
 | |
|    VREG_INDEX_TO_ADDR r2, r2
 | |
|    SET_VREG_WIDE_BY_ADDR r0, r1, r2    // fp[A] <- value
 | |
|    .else
 | |
|    $load   r0, [r0, r1]
 | |
|    dmb     ish
 | |
|    .if $is_object
 | |
|    TEST_IF_MARKING .L${opcode}_mark_after_load
 | |
|    SET_VREG_OBJECT r0, r2              // fp[A] <- value
 | |
|    .else
 | |
|    SET_VREG r0, r2                     // fp[A] <- value
 | |
|    .endif
 | |
|    .endif
 | |
|    FETCH_ADVANCE_INST 2
 | |
|    GET_INST_OPCODE ip
 | |
|    GOTO_OPCODE ip
 | |
| .L${opcode}_slow_path_read_barrier:
 | |
|    bl      art_quick_read_barrier_mark_reg00
 | |
|    b       .L${opcode}_slow_path_resume_after_read_barrier
 | |
| 
 | |
| %def op_sget_wide():
 | |
| %  op_sget(load="ldr", wide="1", is_object="0")
 | |
| 
 | |
| %def op_sget_object():
 | |
| %  op_sget(load="ldr", wide="0", is_object="1")
 | |
| 
 | |
| %def op_sput_boolean():
 | |
| %  op_sput(store="strb", wide="0", is_object="0")
 | |
| 
 | |
| %def op_sput_byte():
 | |
| %  op_sput(store="strb", wide="0", is_object="0")
 | |
| 
 | |
| %def op_sput_char():
 | |
| %  op_sput(store="strh", wide="0", is_object="0")
 | |
| 
 | |
| %def op_sput_short():
 | |
| %  op_sput(store="strh", wide="0", is_object="0")
 | |
| 
 | |
| %def op_sput(store="str", wide="0", is_object="0"):
 | |
| %  slow_path = add_slow_path(op_sput_slow_path, store, wide, is_object)
 | |
|    .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", miss_label=slow_path)
 | |
| .L${opcode}_resume:
 | |
|    ldr     r1, [r0, #ART_FIELD_OFFSET_OFFSET]
 | |
|    ldr     r0, [r0, #ART_FIELD_DECLARING_CLASS_OFFSET]
 | |
|    TEST_IF_MARKING .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
 | |
|    $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
 | |
|    GOTO_OPCODE ip
 | |
| .L${opcode}_read_barrier:
 | |
|    bl      art_quick_read_barrier_mark_reg00
 | |
|    b       .L${opcode}_resume_after_read_barrier
 | |
| 
 | |
| %def op_sput_slow_path(store, wide, is_object):
 | |
|    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
 | |
|    .if $is_object
 | |
|    // Reload the value as it may have moved.
 | |
|    lsr     r4, rINST, #8               // r4 <- A
 | |
|    GET_VREG r4, r4                     // r4 <- v[A]
 | |
|    .endif
 | |
|    tst     r0, #1
 | |
|    beq     .L${opcode}_resume
 | |
|    CLEAR_STATIC_VOLATILE_MARKER r0
 | |
|    ldr     r1, [r0, #ART_FIELD_OFFSET_OFFSET]
 | |
|    ldr     r0, [r0, #ART_FIELD_DECLARING_CLASS_OFFSET]
 | |
|    TEST_IF_MARKING .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
 | |
|    dmb     ish
 | |
|    ATOMIC_STORE64 ip, r2, r3, r0, r1, .L${opcode}_slow_path_atomic_store
 | |
|    dmb     ish
 | |
|    .else
 | |
|    dmb     ish
 | |
|    $store  r4, [r0, r1]
 | |
|    dmb     ish
 | |
|    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
 | |
|    GOTO_OPCODE ip
 | |
| .L${opcode}_slow_path_read_barrier:
 | |
|    bl      art_quick_read_barrier_mark_reg00
 | |
|    b       .L${opcode}_slow_path_resume_after_read_barrier
 | |
| 
 | |
| %def op_sput_wide():
 | |
| %  op_sput(store="str", wide="1", is_object="0")
 | |
| 
 | |
| %def op_sput_object():
 | |
| %  op_sput(store="str", wide="0", is_object="1")
 | |
| 
 | |
| %def op_new_instance():
 | |
|    // The routine is too big to fit in a handler, so jump to it.
 | |
|    EXPORT_PC
 | |
|    // Fast-path which gets the class from thread-local cache.
 | |
| %  fetch_from_thread_cache("r0", miss_label="2f")
 | |
|    TEST_IF_MARKING 3f
 | |
| 4:
 | |
|    ldr     lr, [rSELF, #THREAD_ALLOC_OBJECT_ENTRYPOINT_OFFSET]
 | |
|    blx     lr
 | |
| 1:
 | |
|    lsr     r1, rINST, #8                    // r1 <- A
 | |
|    SET_VREG_OBJECT r0, r1               // fp[A] <- value
 | |
|    FETCH_ADVANCE_INST 2
 | |
|    GET_INST_OPCODE ip
 | |
|    GOTO_OPCODE ip
 | |
| 2:
 | |
|    mov     r0, rSELF
 | |
|    ldr     r1, [sp]
 | |
|    mov     r2, rPC
 | |
|    bl      nterp_get_class_or_allocate_object
 | |
|    b       1b
 | |
| 3:
 | |
|    bl      art_quick_read_barrier_mark_reg00
 | |
|    b       4b
 |