1%def field(helper=""):
2    /*
3     * General field read / write (iget-* iput-* sget-* sput-*).
4     */
5    .extern $helper
6    mov      x0, xPC                       // arg0: Instruction* inst
7    mov      x1, xINST                     // arg1: uint16_t inst_data
8    add      x2, xFP, #OFF_FP_SHADOWFRAME  // arg2: ShadowFrame* sf
9    mov      x3, xSELF                     // arg3: Thread* self
10    PREFETCH_INST 2                        // prefetch next opcode
11    bl       $helper
12    cbz      x0, MterpPossibleException
13    ADVANCE 2
14    GET_INST_OPCODE ip                     // extract opcode from rINST
15    GOTO_OPCODE ip                         // jump to next instruction
16
17%def op_check_cast():
18    /*
19     * Check to see if a cast from one class to another is allowed.
20     */
21    /* check-cast vAA, class//BBBB */
22    EXPORT_PC
23    FETCH    w0, 1                      // w0<- BBBB
24    lsr      w1, wINST, #8              // w1<- AA
25    VREG_INDEX_TO_ADDR x1, w1           // w1<- &object
26    ldr      x2, [xFP, #OFF_FP_METHOD]  // w2<- method
27    mov      x3, xSELF                  // w3<- self
28    bl       MterpCheckCast             // (index, &obj, method, self)
29    PREFETCH_INST 2
30    cbnz     w0, MterpPossibleException
31    ADVANCE  2
32    GET_INST_OPCODE ip                  // extract opcode from rINST
33    GOTO_OPCODE ip                      // jump to next instruction
34
35%def op_iget(is_object=False, is_wide=False, load="ldr", helper="MterpIGetU32"):
36   // Fast-path which gets the field offset from thread-local cache.
37   add      x0, xSELF, #THREAD_INTERPRETER_CACHE_OFFSET       // cache address
38   ubfx     x1, xPC, #2, #THREAD_INTERPRETER_CACHE_SIZE_LOG2  // entry index
39   add      x0, x0, x1, lsl #4            // entry address within the cache
40   ldp      x0, x1, [x0]                  // entry key (pc) and value (offset)
41   lsr      w2, wINST, #12                // B
42   GET_VREG w2, w2                        // object we're operating on
43   cmp      x0, xPC
44%  slow_path_label = add_helper(lambda: field(helper))
45   b.ne     ${slow_path_label}            // cache miss
46   cbz      w2, common_errNullObject      // null object
47%  if is_wide:
48     ldr      x0, [x2, x1]                // x0<- obj.field
49%  else:
50     ${load}  w0, [x2, x1]                // w0<- obj.field
51%  #endif
52%  if is_object:
53     UNPOISON_HEAP_REF w0
54#if defined(USE_READ_BARRIER)
55# if defined(USE_BAKER_READ_BARRIER)
56     ldr    w1, [xSELF, #THREAD_IS_GC_MARKING_OFFSET]
57     cbnz   w1, .L_${opcode}_mark         // GC is active.
58.L_${opcode}_marked:
59# else
60     bl artReadBarrierMark                // x0 <- artReadBarrierMark(x0)
61# endif
62#endif
63%  #endif
64   ubfx     w2, wINST, #8, #4             // w2<- A
65   FETCH_ADVANCE_INST 2                   // advance rPC, load rINST
66%  if is_object:
67     SET_VREG_OBJECT w0, w2               // fp[A]<- w0
68%  elif is_wide:
69     SET_VREG_WIDE x0, w2                 // fp[A]<- x0
70%  else:
71     SET_VREG w0, w2                      // fp[A]<- w0
72%  #endif
73   GET_INST_OPCODE ip                     // extract opcode from rINST
74   GOTO_OPCODE ip                         // jump to next instruction
75%  if is_object:
76#if defined(USE_READ_BARRIER) && defined(USE_BAKER_READ_BARRIER)
77.L_${opcode}_mark:
78     bl artReadBarrierMark                // x0 <- artReadBarrierMark(x0)
79     b .L_${opcode}_marked
80#endif
81%  #endif
82
83%def op_iget_boolean():
84%  op_iget(load="ldrb", helper="MterpIGetU8")
85
86%def op_iget_boolean_quick():
87%  op_iget_quick(load="ldrb")
88
89%def op_iget_byte():
90%  op_iget(load="ldrsb", helper="MterpIGetI8")
91
92%def op_iget_byte_quick():
93%  op_iget_quick(load="ldrsb")
94
95%def op_iget_char():
96%  op_iget(load="ldrh", helper="MterpIGetU16")
97
98%def op_iget_char_quick():
99%  op_iget_quick(load="ldrh")
100
101%def op_iget_object():
102%  op_iget(is_object=True, helper="MterpIGetObj")
103
104%def op_iget_object_quick():
105    /* For: iget-object-quick */
106    /* op vA, vB, offset//CCCC */
107    lsr     w2, wINST, #12              // w2<- B
108    FETCH w1, 1                         // w1<- field byte offset
109    EXPORT_PC
110    GET_VREG w0, w2                     // w0<- object we're operating on
111    bl      artIGetObjectFromMterp      // (obj, offset)
112    ldr     x3, [xSELF, #THREAD_EXCEPTION_OFFSET]
113    ubfx    w2, wINST, #8, #4           // w2<- A
114    PREFETCH_INST 2
115    cbnz    w3, MterpPossibleException      // bail out
116    SET_VREG_OBJECT w0, w2              // fp[A]<- w0
117    ADVANCE 2                           // advance rPC
118    GET_INST_OPCODE ip                  // extract opcode from wINST
119    GOTO_OPCODE ip                      // jump to next instruction
120
121%def op_iget_quick(load="ldr", extend=""):
122    /* For: iget-quick, iget-boolean-quick, iget-byte-quick, iget-char-quick, iget-short-quick */
123    /* op vA, vB, offset//CCCC */
124    lsr     w2, wINST, #12              // w2<- B
125    FETCH w1, 1                         // w1<- field byte offset
126    GET_VREG w3, w2                     // w3<- object we're operating on
127    ubfx    w2, wINST, #8, #4           // w2<- A
128    cbz     w3, common_errNullObject    // object was null
129    $load   w0, [x3, x1]                // w0<- obj.field
130    FETCH_ADVANCE_INST 2                // advance rPC, load rINST
131    $extend
132    SET_VREG w0, w2                     // fp[A]<- w0
133    GET_INST_OPCODE ip                  // extract opcode from rINST
134    GOTO_OPCODE ip                      // jump to next instruction
135
136%def op_iget_short():
137%  op_iget(load="ldrsh", helper="MterpIGetI16")
138
139%def op_iget_short_quick():
140%  op_iget_quick(load="ldrsh")
141
142%def op_iget_wide():
143%  op_iget(is_wide=True, helper="MterpIGetU64")
144
145%def op_iget_wide_quick():
146    /* iget-wide-quick vA, vB, offset//CCCC */
147    lsr     w2, wINST, #12              // w2<- B
148    FETCH w4, 1                         // w4<- field byte offset
149    GET_VREG w3, w2                     // w3<- object we're operating on
150    ubfx    w2, wINST, #8, #4           // w2<- A
151    cbz     w3, common_errNullObject    // object was null
152    ldr     x0, [x3, x4]                // x0<- obj.field
153    FETCH_ADVANCE_INST 2                // advance rPC, load wINST
154    SET_VREG_WIDE x0, w2
155    GET_INST_OPCODE ip                  // extract opcode from wINST
156    GOTO_OPCODE ip                      // jump to next instruction
157
158%def op_instance_of():
159    /*
160     * Check to see if an object reference is an instance of a class.
161     *
162     * Most common situation is a non-null object, being compared against
163     * an already-resolved class.
164     */
165    /* instance-of vA, vB, class//CCCC */
166    EXPORT_PC
167    FETCH     w0, 1                     // w0<- CCCC
168    lsr       w1, wINST, #12            // w1<- B
169    VREG_INDEX_TO_ADDR x1, w1           // w1<- &object
170    ldr       x2, [xFP, #OFF_FP_METHOD] // w2<- method
171    mov       x3, xSELF                 // w3<- self
172    bl        MterpInstanceOf           // (index, &obj, method, self)
173    ldr       x1, [xSELF, #THREAD_EXCEPTION_OFFSET]
174    ubfx      w2, wINST, #8, #4         // w2<- A
175    PREFETCH_INST 2
176    cbnz      x1, MterpException
177    ADVANCE 2                           // advance rPC
178    SET_VREG w0, w2                     // vA<- w0
179    GET_INST_OPCODE ip                  // extract opcode from rINST
180    GOTO_OPCODE ip                      // jump to next instruction
181
182%def op_iput(helper="MterpIPutU32"):
183%  field(helper=helper)
184
185%def op_iput_boolean():
186%  op_iput(helper="MterpIPutU8")
187
188%def op_iput_boolean_quick():
189%  op_iput_quick(store="strb")
190
191%def op_iput_byte():
192%  op_iput(helper="MterpIPutI8")
193
194%def op_iput_byte_quick():
195%  op_iput_quick(store="strb")
196
197%def op_iput_char():
198%  op_iput(helper="MterpIPutU16")
199
200%def op_iput_char_quick():
201%  op_iput_quick(store="strh")
202
203%def op_iput_object():
204%  op_iput(helper="MterpIPutObj")
205
206%def op_iput_object_quick():
207    EXPORT_PC
208    add     x0, xFP, #OFF_FP_SHADOWFRAME
209    mov     x1, xPC
210    mov     w2, wINST
211    bl      MterpIputObjectQuick
212    cbz     w0, MterpException
213    FETCH_ADVANCE_INST 2                // advance rPC, load rINST
214    GET_INST_OPCODE ip                  // extract opcode from rINST
215    GOTO_OPCODE ip                      // jump to next instruction
216
217%def op_iput_quick(store="str"):
218    /* For: iput-quick, iput-object-quick */
219    /* op vA, vB, offset//CCCC */
220    lsr     w2, wINST, #12              // w2<- B
221    FETCH w1, 1                         // w1<- field byte offset
222    GET_VREG w3, w2                     // w3<- fp[B], the object pointer
223    ubfx    w2, wINST, #8, #4           // w2<- A
224    cbz     w3, common_errNullObject    // object was null
225    GET_VREG w0, w2                     // w0<- fp[A]
226    FETCH_ADVANCE_INST 2                // advance rPC, load rINST
227    $store     w0, [x3, x1]             // obj.field<- w0
228    GET_INST_OPCODE ip                  // extract opcode from rINST
229    GOTO_OPCODE ip                      // jump to next instruction
230
231%def op_iput_short():
232%  op_iput(helper="MterpIPutI16")
233
234%def op_iput_short_quick():
235%  op_iput_quick(store="strh")
236
237%def op_iput_wide():
238%  op_iput(helper="MterpIPutU64")
239
240%def op_iput_wide_quick():
241    /* iput-wide-quick vA, vB, offset//CCCC */
242    lsr     w2, wINST, #12              // w2<- B
243    FETCH w3, 1                         // w3<- field byte offset
244    GET_VREG w2, w2                     // w2<- fp[B], the object pointer
245    ubfx    w0, wINST, #8, #4           // w0<- A
246    cbz     w2, common_errNullObject    // object was null
247    GET_VREG_WIDE x0, w0                // x0<- fp[A]
248    FETCH_ADVANCE_INST 2                // advance rPC, load wINST
249    str     x0, [x2, x3]                // obj.field<- x0
250    GET_INST_OPCODE ip                  // extract opcode from wINST
251    GOTO_OPCODE ip                      // jump to next instruction
252
253%def op_new_instance():
254    /*
255     * Create a new instance of a class.
256     */
257    /* new-instance vAA, class//BBBB */
258    EXPORT_PC
259    add     x0, xFP, #OFF_FP_SHADOWFRAME
260    mov     x1, xSELF
261    mov     w2, wINST
262    bl      MterpNewInstance           // (shadow_frame, self, inst_data)
263    cbz     w0, MterpPossibleException
264    FETCH_ADVANCE_INST 2               // advance rPC, load rINST
265    GET_INST_OPCODE ip                 // extract opcode from rINST
266    GOTO_OPCODE ip                     // jump to next instruction
267
268%def op_sget(helper="MterpSGetU32"):
269%  field(helper=helper)
270
271%def op_sget_boolean():
272%  op_sget(helper="MterpSGetU8")
273
274%def op_sget_byte():
275%  op_sget(helper="MterpSGetI8")
276
277%def op_sget_char():
278%  op_sget(helper="MterpSGetU16")
279
280%def op_sget_object():
281%  op_sget(helper="MterpSGetObj")
282
283%def op_sget_short():
284%  op_sget(helper="MterpSGetI16")
285
286%def op_sget_wide():
287%  op_sget(helper="MterpSGetU64")
288
289%def op_sput(helper="MterpSPutU32"):
290%  field(helper=helper)
291
292%def op_sput_boolean():
293%  op_sput(helper="MterpSPutU8")
294
295%def op_sput_byte():
296%  op_sput(helper="MterpSPutI8")
297
298%def op_sput_char():
299%  op_sput(helper="MterpSPutU16")
300
301%def op_sput_object():
302%  op_sput(helper="MterpSPutObj")
303
304%def op_sput_short():
305%  op_sput(helper="MterpSPutI16")
306
307%def op_sput_wide():
308%  op_sput(helper="MterpSPutU64")
309