blob: 769747efa9382a9cf5e423c4bcbc015e2b22660a [file] [log] [blame]
// array-length vA, vB
// Format 12x: B|A|21
// Store in the given destination register the length of the indicated array, in entries
%def op_array_length():
srliw t0, xINST, 12 // t0 := B
GET_VREG_OBJECT t0, t0 // t0 := refs[B]
beqz t0, 1f
srliw t1, xINST, 8 // t1 := B|A
FETCH_ADVANCE_INST 1
andi t1, t1, 0xF // t1 := A
GET_INST_OPCODE t3
lw t2, MIRROR_ARRAY_LENGTH_OFFSET(t0)
% set_vreg("t2", "t1", z0="t0")
GOTO_OPCODE t3
1:
tail common_errNullObject
// new-array vA, vB, type@CCCC
// 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():
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
// Format 35c: A|G|24 BBBB F|E|D|C
// Construct an array of the given type and size, filling it with the supplied contents. The type
// must be an array type. The array's contents must be single-word (that is, no arrays of long or
// double, but reference types are acceptable). The constructed instance is stored as a "result" in
// the same way that the method invocation instructions store their results, so the constructed
// instance must be moved to a register with an immediately subsequent move-result-object
// instruction (if it is to be used).
%def op_filled_new_array(is_range=False):
EXPORT_PC
mv a0, xSELF
ld a1, (sp) // a1 := caller ArtMethod*
mv a2, xFP // a2 := vreg array
mv a3, xPC
% if is_range:
call nterp_filled_new_array_range // args a0, a1, a2, a3
% else:
call nterp_filled_new_array // args a0, a1, a2, a3
%#:
FETCH_ADVANCE_INST 3
GET_INST_OPCODE t0
GOTO_OPCODE t0
// filled-new-array/range {vCCCC .. vNNNN}, type@BBBB
// where NNNN = CCCC + AA - 1
// Format 3rc: AA|25 BBBB CCCC
// Construct an array of the given type and size, filling it with the supplied contents.
// Clarifications and restrictions are the same as filled-new-array, described above.
%def op_filled_new_array_range():
% op_filled_new_array(is_range=True)
// fill-array-data vAA, +BBBBBBBB
// Format 31t: AA|26 BBBB(lo) BBBB(hi)
// Fill the given array with the indicated data. The reference must be to an array of primitives,
// and the data table must match it in type and must contain no more elements than will fit in the
// array. That is, the array may be larger than the table, and if so, only the initial elements of
// the array are set, leaving the remainder alone.
%def op_fill_array_data():
EXPORT_PC
srliw t0, xINST, 8 // t0 := AA
FETCH t1, count=1, signed=1, width=32
// t1 := ssssssssBBBBBBBB
GET_VREG_OBJECT a1, t0 // a1 := refs[AA] (array ref)
// +BBBBBBBB offset is in code units. Multiply by 2 for byte offset against dex PC.
sh1add a0, t1, xPC // a0 := payload address
call art_quick_handle_fill_data // args a0, a1
FETCH_ADVANCE_INST 3
GET_INST_OPCODE t0
GOTO_OPCODE t0
// Common setup across APUT and AGET variants.
// Sets \array, \index, and \length registers.
// Branches to null handler and out-of-bounds handler.
%def array_prelude(array, index, length, null_label, oob_label):
FETCH $index, count=1 // index := CC|BB
andi $array, $index, 0xFF // array := BB
GET_VREG_OBJECT $array, $array // array := refs[BB], array obj
beqz $array, $null_label
srliw $index, $index, 8 // index := CC
% get_vreg(index, index) # index := fp[CC]
lw $length, MIRROR_ARRAY_LENGTH_OFFSET($array) // length (signed 32b)
bgeu $index, $length, $oob_label // Unsigned comparison also catches negative index.
// aget vAA, vBB, vCC
// Format 23x: AA|44 CC|BB
// vAA := vBB[vCC]
%def op_aget(width=32, zext=False):
% array_prelude(array="t0", index="a0", length="a1", null_label=f".L{opcode}_null", oob_label=f".L{opcode}_oob")
// t0 := vBB array object, a0 := vCC index, a1 := array length
% if width == 8 and zext:
add t0, a0, t0
lbu t0, MIRROR_BOOLEAN_ARRAY_DATA_OFFSET(t0)
% elif width == 8:
add t0, a0, t0
lb t0, MIRROR_BYTE_ARRAY_DATA_OFFSET(t0)
% elif width == 16 and zext:
sh1add t0, a0, t0
lhu t0, MIRROR_CHAR_ARRAY_DATA_OFFSET(t0)
% elif width == 16:
sh1add t0, a0, t0
lh t0, MIRROR_SHORT_ARRAY_DATA_OFFSET(t0)
% elif width == 32:
sh2add t0, a0, t0
lw t0, MIRROR_INT_ARRAY_DATA_OFFSET(t0)
% elif width == 64:
sh3add t0, a0, t0
ld t0, MIRROR_WIDE_ARRAY_DATA_OFFSET(t0)
% else:
% assert False, width
%#:
// t0 := *(array obj + data offset + idx * elem_size)
srliw t1, xINST, 8 // t1 := AA
% set_vreg("t0", "t1", z0="t2", width=width)
FETCH_ADVANCE_INST 2
GET_INST_OPCODE t0
GOTO_OPCODE t0
.L${opcode}_null:
tail common_errNullObject
.L${opcode}_oob:
tail common_errArrayIndex // args a0 (index), a1 (length)
// aget-wide vAA, vBB, vCC
// Format 23x: AA|45 CC|BB
%def op_aget_wide():
% op_aget(width=64)
// aget-object vAA, vBB, vCC
// Format 23x: AA|46 CC|BB
%def op_aget_object():
% array_prelude(array="t0", index="a0", length="a1", null_label=f".L{opcode}_null", oob_label=f".L{opcode}_oob")
// t0 := vBB array object, a0 := vCC index, a1 := array length
sh2add t0, a0, t0
lwu a0, MIRROR_OBJECT_ARRAY_DATA_OFFSET(t0)
// a0 := *(array obj + data offset + idx * elem_size)
UNPOISON_HEAP_REF a0
TEST_IF_MARKING t1, .L${opcode}_mark
.L${opcode}_mark_resume:
srliw t1, xINST, 8 // t1 := AA
SET_VREG_OBJECT a0, t1, z0=t2
FETCH_ADVANCE_INST 2
GET_INST_OPCODE t0
GOTO_OPCODE t0
.L${opcode}_mark:
call art_quick_read_barrier_mark_reg10 // a0, object elem
j .L${opcode}_mark_resume
.L${opcode}_null:
tail common_errNullObject
.L${opcode}_oob:
tail common_errArrayIndex // args a0 (index), a1 (length)
// aget-boolean vAA, vBB, vCC
// Format 23x: AA|47 CC|BB
%def op_aget_boolean():
% op_aget(width=8, zext=True)
// aget-byte vAA, vBB, vCC
// Format 23x: AA|48 CC|BB
%def op_aget_byte():
% op_aget(width=8)
// aget_char vAA, vBB, vCC
// Format 23x: AA|49 CC|BB
%def op_aget_char():
% op_aget(width=16, zext=True)
// aget-short vAA, vBB, vCC
// Format 23x: AA|4a CC|BB
%def op_aget_short():
% op_aget(width=16)
// aput vAA, vBB, vCC
// Format 23x: AA|4b CC|BB
// vBB[vCC] := vAA
%def op_aput(width=32, zext=False):
% array_prelude(array="t0", index="t1", length="t2", null_label=f".L{opcode}_null", oob_label=f".L{opcode}_oob")
// t0 := vBB array object, t1 := vCC zext index, t2 := array length
srliw t2, xINST, 8 // t2 := AA
% get_vreg("t2", "t2", width=width) # t2 := fp[AA]
% if width == 8 and zext:
add t0, t1, t0
sb t2, MIRROR_BOOLEAN_ARRAY_DATA_OFFSET(t0)
% elif width == 8:
add t0, t1, t0
sb t2, MIRROR_BYTE_ARRAY_DATA_OFFSET(t0)
% elif width == 16 and zext:
sh1add t0, t1, t0
sh t2, MIRROR_CHAR_ARRAY_DATA_OFFSET(t0)
% elif width == 16:
sh1add t0, t1, t0
sh t2, MIRROR_SHORT_ARRAY_DATA_OFFSET(t0)
% elif width == 32:
sh2add t0, t1, t0
sw t2, MIRROR_INT_ARRAY_DATA_OFFSET(t0)
% elif width == 64:
sh3add t0, t1, t0
sd t2, MIRROR_WIDE_ARRAY_DATA_OFFSET(t0)
% else:
% assert False, width
%#:
FETCH_ADVANCE_INST 2
GET_INST_OPCODE t0
GOTO_OPCODE t0
.L${opcode}_null:
tail common_errNullObject
.L${opcode}_oob:
sext.w a0, t1
mv a1, t2
tail common_errArrayIndex // args a0 (index), a1 (length)
// aput-wide vAA, vBB, vCC
// Format 23x: AA|4c CC|BB
%def op_aput_wide():
% op_aput(width=64)
// aput-object vAA, vBB, vCC
// Format 23x: AA|4d CC|BB
%def op_aput_object():
% array_prelude(array="a0", index="a1", length="a2", null_label=f".L{opcode}_null", oob_label=f".L{opcode}_oob")
// a0 := vBB array object, a1 := vCC zext index, a2 := array length
EXPORT_PC
srliw a2, xINST, 8 // a2 := AA
GET_VREG_OBJECT a2, a2 // a2 := fp[AA]
sext.w a1, a1 // a1 := sext index
call art_quick_aput_obj // args a0 (array obj), a1 (index), a2 (obj)
FETCH_ADVANCE_INST 2
GET_INST_OPCODE t0
GOTO_OPCODE t0
.L${opcode}_null:
tail common_errNullObject
.L${opcode}_oob:
sext.w a0, a1
mv a1, a2
tail common_errArrayIndex // args a0 (index), a1 (length)
// aput-boolean vAA, vBB, vCC
// Format 23x: AA|4e CC|BB
%def op_aput_boolean():
% op_aput(width=8, zext=True)
// aput-byte vAA, vBB, vCC
// Format 23x: AA|4f CC|BB
%def op_aput_byte():
% op_aput(width=8)
// aput-char vAA, vBB, vCC
// Format 23x: AA|50 CC|BB
%def op_aput_char():
% op_aput(width=16, zext=True)
// aput-short vAA, vBB, vCC
// Format 23x: AA|51 CC|BB
%def op_aput_short():
% op_aput(width=16)