blob: 3cc688e5e2efd9502e9b9b5ac7be902674ab9205 [file] [log] [blame]
%def field(helper=""):
/*
* General field read / write (iget-* iput-* sget-* sput-*).
*/
.extern $helper
mov x0, xPC // arg0: Instruction* inst
mov x1, xINST // arg1: uint16_t inst_data
add x2, xFP, #OFF_FP_SHADOWFRAME // arg2: ShadowFrame* sf
mov x3, xSELF // arg3: Thread* self
PREFETCH_INST 2 // prefetch next opcode
bl $helper
cbz x0, MterpPossibleException
ADVANCE 2
GET_INST_OPCODE ip // extract opcode from rINST
GOTO_OPCODE ip // jump to next instruction
%def op_check_cast():
/*
* Check to see if a cast from one class to another is allowed.
*/
/* check-cast vAA, class//BBBB */
EXPORT_PC
FETCH w0, 1 // w0<- BBBB
lsr w1, wINST, #8 // w1<- AA
VREG_INDEX_TO_ADDR x1, w1 // w1<- &object
ldr x2, [xFP, #OFF_FP_METHOD] // w2<- method
mov x3, xSELF // w3<- self
bl MterpCheckCast // (index, &obj, method, self)
PREFETCH_INST 2
cbnz w0, MterpPossibleException
ADVANCE 2
GET_INST_OPCODE ip // extract opcode from rINST
GOTO_OPCODE ip // jump to next instruction
%def op_iget(is_object=False, is_wide=False, load="ldr", helper="MterpIGetU32"):
// Fast-path which gets the field offset from thread-local cache.
add x0, xSELF, #THREAD_INTERPRETER_CACHE_OFFSET // cache address
ubfx x1, xPC, #2, #THREAD_INTERPRETER_CACHE_SIZE_LOG2 // entry index
add x0, x0, x1, lsl #4 // entry address within the cache
ldp x0, x1, [x0] // entry key (pc) and value (offset)
lsr w2, wINST, #12 // B
GET_VREG w2, w2 // object we're operating on
cmp x0, xPC
% slow_path_label = add_helper(lambda: field(helper))
b.ne ${slow_path_label} // cache miss
cbz w2, common_errNullObject // null object
% if is_wide:
ldr x0, [x2, x1] // x0<- obj.field
% else:
${load} w0, [x2, x1] // w0<- obj.field
% #endif
% if is_object:
UNPOISON_HEAP_REF w0
#if defined(USE_READ_BARRIER)
# if defined(USE_BAKER_READ_BARRIER)
ldr w1, [xSELF, #THREAD_IS_GC_MARKING_OFFSET]
cbnz w1, .L_${opcode}_mark // GC is active.
.L_${opcode}_marked:
# else
bl artReadBarrierMark // x0 <- artReadBarrierMark(x0)
# endif
#endif
% #endif
ubfx w2, wINST, #8, #4 // w2<- A
FETCH_ADVANCE_INST 2 // advance rPC, load rINST
% if is_object:
SET_VREG_OBJECT w0, w2 // fp[A]<- w0
% elif is_wide:
SET_VREG_WIDE x0, w2 // fp[A]<- x0
% else:
SET_VREG w0, w2 // fp[A]<- w0
% #endif
GET_INST_OPCODE ip // extract opcode from rINST
GOTO_OPCODE ip // jump to next instruction
% if is_object:
#if defined(USE_READ_BARRIER) && defined(USE_BAKER_READ_BARRIER)
.L_${opcode}_mark:
bl artReadBarrierMark // x0 <- artReadBarrierMark(x0)
b .L_${opcode}_marked
#endif
% #endif
%def op_iget_boolean():
% op_iget(load="ldrb", helper="MterpIGetU8")
%def op_iget_boolean_quick():
% op_iget_quick(load="ldrb")
%def op_iget_byte():
% op_iget(load="ldrsb", helper="MterpIGetI8")
%def op_iget_byte_quick():
% op_iget_quick(load="ldrsb")
%def op_iget_char():
% op_iget(load="ldrh", helper="MterpIGetU16")
%def op_iget_char_quick():
% op_iget_quick(load="ldrh")
%def op_iget_object():
% op_iget(is_object=True, helper="MterpIGetObj")
%def op_iget_object_quick():
/* For: iget-object-quick */
/* op vA, vB, offset//CCCC */
lsr w2, wINST, #12 // w2<- B
FETCH w1, 1 // w1<- field byte offset
EXPORT_PC
GET_VREG w0, w2 // w0<- object we're operating on
bl artIGetObjectFromMterp // (obj, offset)
ldr x3, [xSELF, #THREAD_EXCEPTION_OFFSET]
ubfx w2, wINST, #8, #4 // w2<- A
PREFETCH_INST 2
cbnz w3, MterpPossibleException // bail out
SET_VREG_OBJECT w0, w2 // fp[A]<- w0
ADVANCE 2 // advance rPC
GET_INST_OPCODE ip // extract opcode from wINST
GOTO_OPCODE ip // jump to next instruction
%def op_iget_quick(load="ldr", extend=""):
/* For: iget-quick, iget-boolean-quick, iget-byte-quick, iget-char-quick, iget-short-quick */
/* op vA, vB, offset//CCCC */
lsr w2, wINST, #12 // w2<- B
FETCH w1, 1 // w1<- field byte offset
GET_VREG w3, w2 // w3<- object we're operating on
ubfx w2, wINST, #8, #4 // w2<- A
cbz w3, common_errNullObject // object was null
$load w0, [x3, x1] // w0<- obj.field
FETCH_ADVANCE_INST 2 // advance rPC, load rINST
$extend
SET_VREG w0, w2 // fp[A]<- w0
GET_INST_OPCODE ip // extract opcode from rINST
GOTO_OPCODE ip // jump to next instruction
%def op_iget_short():
% op_iget(load="ldrsh", helper="MterpIGetI16")
%def op_iget_short_quick():
% op_iget_quick(load="ldrsh")
%def op_iget_wide():
% op_iget(is_wide=True, helper="MterpIGetU64")
%def op_iget_wide_quick():
/* iget-wide-quick vA, vB, offset//CCCC */
lsr w2, wINST, #12 // w2<- B
FETCH w4, 1 // w4<- field byte offset
GET_VREG w3, w2 // w3<- object we're operating on
ubfx w2, wINST, #8, #4 // w2<- A
cbz w3, common_errNullObject // object was null
ldr x0, [x3, x4] // x0<- obj.field
FETCH_ADVANCE_INST 2 // advance rPC, load wINST
SET_VREG_WIDE x0, w2
GET_INST_OPCODE ip // extract opcode from wINST
GOTO_OPCODE ip // jump to next instruction
%def op_instance_of():
/*
* Check to see if an object reference is an instance of a class.
*
* Most common situation is a non-null object, being compared against
* an already-resolved class.
*/
/* instance-of vA, vB, class//CCCC */
EXPORT_PC
FETCH w0, 1 // w0<- CCCC
lsr w1, wINST, #12 // w1<- B
VREG_INDEX_TO_ADDR x1, w1 // w1<- &object
ldr x2, [xFP, #OFF_FP_METHOD] // w2<- method
mov x3, xSELF // w3<- self
bl MterpInstanceOf // (index, &obj, method, self)
ldr x1, [xSELF, #THREAD_EXCEPTION_OFFSET]
ubfx w2, wINST, #8, #4 // w2<- A
PREFETCH_INST 2
cbnz x1, MterpException
ADVANCE 2 // advance rPC
SET_VREG w0, w2 // vA<- w0
GET_INST_OPCODE ip // extract opcode from rINST
GOTO_OPCODE ip // jump to next instruction
%def op_iput(helper="MterpIPutU32"):
% field(helper=helper)
%def op_iput_boolean():
% op_iput(helper="MterpIPutU8")
%def op_iput_boolean_quick():
% op_iput_quick(store="strb")
%def op_iput_byte():
% op_iput(helper="MterpIPutI8")
%def op_iput_byte_quick():
% op_iput_quick(store="strb")
%def op_iput_char():
% op_iput(helper="MterpIPutU16")
%def op_iput_char_quick():
% op_iput_quick(store="strh")
%def op_iput_object():
% op_iput(helper="MterpIPutObj")
%def op_iput_object_quick():
EXPORT_PC
add x0, xFP, #OFF_FP_SHADOWFRAME
mov x1, xPC
mov w2, wINST
bl MterpIputObjectQuick
cbz w0, MterpException
FETCH_ADVANCE_INST 2 // advance rPC, load rINST
GET_INST_OPCODE ip // extract opcode from rINST
GOTO_OPCODE ip // jump to next instruction
%def op_iput_quick(store="str"):
/* For: iput-quick, iput-object-quick */
/* op vA, vB, offset//CCCC */
lsr w2, wINST, #12 // w2<- B
FETCH w1, 1 // w1<- field byte offset
GET_VREG w3, w2 // w3<- fp[B], the object pointer
ubfx w2, wINST, #8, #4 // w2<- A
cbz w3, common_errNullObject // object was null
GET_VREG w0, w2 // w0<- fp[A]
FETCH_ADVANCE_INST 2 // advance rPC, load rINST
$store w0, [x3, x1] // obj.field<- w0
GET_INST_OPCODE ip // extract opcode from rINST
GOTO_OPCODE ip // jump to next instruction
%def op_iput_short():
% op_iput(helper="MterpIPutI16")
%def op_iput_short_quick():
% op_iput_quick(store="strh")
%def op_iput_wide():
% op_iput(helper="MterpIPutU64")
%def op_iput_wide_quick():
/* iput-wide-quick vA, vB, offset//CCCC */
lsr w2, wINST, #12 // w2<- B
FETCH w3, 1 // w3<- field byte offset
GET_VREG w2, w2 // w2<- fp[B], the object pointer
ubfx w0, wINST, #8, #4 // w0<- A
cbz w2, common_errNullObject // object was null
GET_VREG_WIDE x0, w0 // x0<- fp[A]
FETCH_ADVANCE_INST 2 // advance rPC, load wINST
str x0, [x2, x3] // obj.field<- x0
GET_INST_OPCODE ip // extract opcode from wINST
GOTO_OPCODE ip // jump to next instruction
%def op_new_instance():
/*
* Create a new instance of a class.
*/
/* new-instance vAA, class//BBBB */
EXPORT_PC
add x0, xFP, #OFF_FP_SHADOWFRAME
mov x1, xSELF
mov w2, wINST
bl MterpNewInstance // (shadow_frame, self, inst_data)
cbz w0, MterpPossibleException
FETCH_ADVANCE_INST 2 // advance rPC, load rINST
GET_INST_OPCODE ip // extract opcode from rINST
GOTO_OPCODE ip // jump to next instruction
%def op_sget(helper="MterpSGetU32"):
% field(helper=helper)
%def op_sget_boolean():
% op_sget(helper="MterpSGetU8")
%def op_sget_byte():
% op_sget(helper="MterpSGetI8")
%def op_sget_char():
% op_sget(helper="MterpSGetU16")
%def op_sget_object():
% op_sget(helper="MterpSGetObj")
%def op_sget_short():
% op_sget(helper="MterpSGetI16")
%def op_sget_wide():
% op_sget(helper="MterpSGetU64")
%def op_sput(helper="MterpSPutU32"):
% field(helper=helper)
%def op_sput_boolean():
% op_sput(helper="MterpSPutU8")
%def op_sput_byte():
% op_sput(helper="MterpSPutI8")
%def op_sput_char():
% op_sput(helper="MterpSPutU16")
%def op_sput_object():
% op_sput(helper="MterpSPutObj")
%def op_sput_short():
% op_sput(helper="MterpSPutI16")
%def op_sput_wide():
% op_sput(helper="MterpSPutU64")