1 /*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 /*! \file LowerObject.cpp
18 \brief This file lowers the following bytecodes: CHECK_CAST,
19 */
20 #include "libdex/DexOpcodes.h"
21 #include "libdex/DexFile.h"
22 #include "Lower.h"
23 #include "NcgAot.h"
24 #include "enc_wrapper.h"
25
26 extern void markCard_filled(int tgtAddrReg, bool isTgtPhysical, int scratchReg, bool isScratchPhysical);
27
28 #define P_GPR_1 PhysicalReg_EBX
29 #define P_GPR_2 PhysicalReg_ECX
30 #define P_GPR_3 PhysicalReg_ESI
31 //! LOWER bytecode CHECK_CAST and INSTANCE_OF
32 //! CALL class_resolve (%ebx is live across the call)
33 //! dvmInstanceofNonTrivial
34 //! NO register is live through function check_cast_helper
check_cast_nohelper(u2 vA,u4 tmp,bool instance,u2 vDest)35 int check_cast_nohelper(u2 vA, u4 tmp, bool instance, u2 vDest) {
36 get_virtual_reg(vA, OpndSize_32, 1, false); //object
37 scratchRegs[2] = PhysicalReg_Null; scratchRegs[3] = PhysicalReg_Null;
38 /* for trace-based JIT, it is likely that the class is already resolved */
39 bool needToResolve = true;
40 ClassObject *classPtr =
41 (currentMethod->clazz->pDvmDex->pResClasses[tmp]);
42 ALOGV("in check_cast, class is resolved to %p", classPtr);
43 if(classPtr != NULL) {
44 needToResolve = false;
45 ALOGV("check_cast class %s", classPtr->descriptor);
46 }
47 if(needToResolve) {
48 //get_res_classes is moved here for NCG O1 to improve performance of GLUE optimization
49 scratchRegs[0] = PhysicalReg_SCRATCH_1; scratchRegs[1] = PhysicalReg_SCRATCH_2;
50 get_res_classes(4, false);
51 }
52 compare_imm_reg(OpndSize_32, 0, 1, false);
53
54 rememberState(1);
55 //for private code cache, previously it jumped to .instance_of_okay_1
56 //if object reference is null, jump to the handler for this special case
57 if(instance) {
58 conditional_jump(Condition_E, ".instance_of_null", true);
59 }
60 else {
61 conditional_jump(Condition_E, ".check_cast_null", true);
62 }
63 //check whether the class is already resolved
64 //if yes, jump to check_cast_resolved
65 //if not, call class_resolve
66 if(needToResolve) {
67 move_mem_to_reg(OpndSize_32, tmp*4, 4, false, PhysicalReg_EAX, true);
68 compare_imm_reg(OpndSize_32, 0, PhysicalReg_EAX, true);
69 if(instance)
70 conditional_jump(Condition_NE, ".instance_of_resolved", true);
71 else
72 conditional_jump(Condition_NE, ".check_cast_resolved", true);
73 //try to resolve the class
74 rememberState(2);
75 move_imm_to_reg(OpndSize_32, tmp, PhysicalReg_EAX, true);
76 export_pc(); //trying to resolve the class
77 call_helper_API(".class_resolve");
78 transferToState(2);
79 } //needToResolve
80 else {
81 /* the class is already resolved and is constant */
82 move_imm_to_reg(OpndSize_32, (int)classPtr, PhysicalReg_EAX, true);
83 }
84 //class is resolved, and it is in %eax
85 if(!instance) {
86 insertLabel(".check_cast_resolved", true);
87 }
88 else insertLabel(".instance_of_resolved", true);
89
90 move_mem_to_reg(OpndSize_32, offObject_clazz, 1, false, 6, false); //object->clazz
91
92 //%eax: resolved class
93 //compare resolved class and object->clazz
94 //if the same, jump to the handler for this special case
95 compare_reg_reg(PhysicalReg_EAX, true, 6, false);
96 rememberState(3);
97 if(instance) {
98 conditional_jump(Condition_E, ".instance_of_equal", true);
99 } else {
100 conditional_jump(Condition_E, ".check_cast_equal", true);
101 }
102
103 //prepare to call dvmInstanceofNonTrivial
104 //INPUT: the resolved class & object reference
105 load_effective_addr(-8, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
106 move_reg_to_mem(OpndSize_32, 6, false, 0, PhysicalReg_ESP, true);
107 move_reg_to_mem(OpndSize_32, PhysicalReg_EAX, true, 4, PhysicalReg_ESP, true); //resolved class
108 scratchRegs[0] = PhysicalReg_SCRATCH_3;
109 nextVersionOfHardReg(PhysicalReg_EAX, 2); //next version has 2 refs
110 call_dvmInstanceofNonTrivial();
111 load_effective_addr(8, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
112 //
113 if(instance) {
114 //move return value to P_GPR_2
115 move_reg_to_reg(OpndSize_32, PhysicalReg_EAX, true, 3, false);
116 rememberState(4);
117 unconditional_jump(".instance_of_okay", true);
118 } else {
119 //if return value of dvmInstanceofNonTrivial is zero, throw exception
120 compare_imm_reg(OpndSize_32, 0, PhysicalReg_EAX, true);
121 rememberState(4);
122 conditional_jump(Condition_NE, ".check_cast_okay", true);
123 //two inputs for common_throw_message: object reference in eax, exception pointer in ecx
124 nextVersionOfHardReg(PhysicalReg_EAX, 1); //next version has 1 ref
125 move_reg_to_reg(OpndSize_32, 1, false, PhysicalReg_EAX, true);
126
127 load_imm_global_data_API("strClassCastExceptionPtr", OpndSize_32, PhysicalReg_ECX, true);
128
129 nextVersionOfHardReg(PhysicalReg_EDX, 2); //next version has 2 ref count
130 export_pc();
131
132 unconditional_jump_global_API("common_throw_message", false);
133 }
134 //handler for speical case where object reference is null
135 if(instance)
136 insertLabel(".instance_of_null", true);
137 else insertLabel(".check_cast_null", true);
138 goToState(1);
139 if(instance) {
140 move_imm_to_reg(OpndSize_32, 0, 3, false);
141 }
142 transferToState(4);
143 if(instance)
144 unconditional_jump(".instance_of_okay", true);
145 else
146 unconditional_jump(".check_cast_okay", true);
147
148 //handler for special case where class of object is the same as the resolved class
149 if(instance)
150 insertLabel(".instance_of_equal", true);
151 else insertLabel(".check_cast_equal", true);
152 goToState(3);
153 if(instance) {
154 move_imm_to_reg(OpndSize_32, 1, 3, false);
155 }
156 transferToState(4);
157 if(instance)
158 insertLabel(".instance_of_okay", true);
159 else insertLabel(".check_cast_okay", true);
160 //all cases merge here and the value is put to virtual register
161 if(instance) {
162 set_virtual_reg(vDest, OpndSize_32, 3, false);
163 }
164 return 0;
165 }
166 //! common code to lower CHECK_CAST & INSTANCE_OF
167
168 //!
common_check_cast_instance_of(u2 vA,u4 tmp,bool instance,u2 vDest)169 int common_check_cast_instance_of(u2 vA, u4 tmp, bool instance, u2 vDest) {
170 return check_cast_nohelper(vA, tmp, instance, vDest);
171 }
172 #undef P_GPR_1
173 #undef P_GPR_2
174 #undef P_GPR_3
175
176 //! LOWER bytecode CHECK_CAST
177
178 //!
op_check_cast()179 int op_check_cast() {
180 u2 vA = INST_AA(inst);
181 u4 tmp = (u4)FETCH(1);
182 common_check_cast_instance_of(vA, tmp, false, 0);
183 rPC += 2;
184 return 0;
185 }
186 //!LOWER bytecode INSTANCE_OF
187
188 //!
op_instance_of()189 int op_instance_of() {
190 u2 vB = INST_B(inst);
191 u2 vA = INST_A(inst);
192 u4 tmp = (u4)FETCH(1);
193 common_check_cast_instance_of(vB, tmp, true, vA);
194 rPC += 2;
195 return 0;
196 }
197
198 #define P_GPR_1 PhysicalReg_EBX
199 #define P_GPR_2 PhysicalReg_ECX
200 //! LOWER bytecode MONITOR_ENTER without usage of helper function
201
202 //! CALL dvmLockObject
monitor_enter_nohelper(u2 vA)203 int monitor_enter_nohelper(u2 vA) {
204 scratchRegs[0] = PhysicalReg_SCRATCH_1;
205 scratchRegs[2] = PhysicalReg_Null; scratchRegs[3] = PhysicalReg_Null;
206
207 requestVRFreeDelay(vA,VRDELAY_NULLCHECK); // Request VR delay before transfer to temporary
208 //get_self_pointer is separated
209 get_virtual_reg(vA, OpndSize_32, 1, false);
210 //to optimize redundant null check, NCG O1 wraps up null check in a function: nullCheck
211 get_self_pointer(3, false);
212 nullCheck(1, false, 1, vA); //maybe optimized away
213 cancelVRFreeDelayRequest(vA,VRDELAY_NULLCHECK);
214
215 /////////////////////////////
216 //prepare to call dvmLockObject, inputs: object reference and self
217 // TODO: Should reset inJitCodeCache before calling dvmLockObject
218 // so that code cache can be reset if needed when locking object
219 // taking a long time. Not resetting inJitCodeCache may delay
220 // code cache reset when code cache is full, preventing traces from
221 // JIT compilation. This has performance implication.
222 // However, after resetting inJitCodeCache, the code should be
223 // wrapped in a helper instead of directly inlined in code cache.
224 // If the code after dvmLockObject call is in code cache and the code
225 // cache is reset during dvmLockObject call, execution after
226 // dvmLockObject will return to a cleared code cache region,
227 // resulting in seg fault.
228 load_effective_addr(-8, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
229 move_reg_to_mem(OpndSize_32, 1, false, 4, PhysicalReg_ESP, true);
230 move_reg_to_mem(OpndSize_32, 3, false, 0, PhysicalReg_ESP, true);
231 scratchRegs[0] = PhysicalReg_SCRATCH_2;
232 call_dvmLockObject();
233 load_effective_addr(8, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
234 /////////////////////////////
235 return 0;
236 }
237 //! lower bytecode MONITOR_ENTER
238
239 //! It will use helper function if switch is on
op_monitor_enter()240 int op_monitor_enter() {
241 u2 vA = INST_AA(inst);
242 export_pc();
243 monitor_enter_nohelper(vA);
244 rPC += 1;
245 return 0;
246 }
247 #undef P_GPR_1
248 #undef P_GPR_2
249
250 #define P_GPR_1 PhysicalReg_EBX
251 #define P_GPR_2 PhysicalReg_ECX
252 //! lower bytecode MONITOR_EXIT
253
254 //! It will use helper function if switch is on
op_monitor_exit()255 int op_monitor_exit() {
256 u2 vA = INST_AA(inst);
257 ////////////////////
258 //LOWER bytecode MONITOR_EXIT without helper function
259 // CALL dvmUnlockObject
260 scratchRegs[0] = PhysicalReg_SCRATCH_1; scratchRegs[1] = PhysicalReg_SCRATCH_2;
261 scratchRegs[2] = PhysicalReg_Null; scratchRegs[3] = PhysicalReg_Null;
262 requestVRFreeDelay(vA,VRDELAY_NULLCHECK); // Request VR delay before transfer to temporary
263 get_virtual_reg(vA, OpndSize_32, 1, false);
264 nullCheck(1, false, 1, vA); //maybe optimized away
265 cancelVRFreeDelayRequest(vA,VRDELAY_NULLCHECK);
266
267 /////////////////////////////
268 //prepare to call dvmUnlockObject, inputs: object reference and self
269 push_reg_to_stack(OpndSize_32, 1, false);
270 push_mem_to_stack(OpndSize_32, offEBP_self, PhysicalReg_EBP, true);
271 scratchRegs[0] = PhysicalReg_SCRATCH_2;
272 call_dvmUnlockObject();
273 compare_imm_reg(OpndSize_32, 0, PhysicalReg_EAX, true);
274 load_effective_addr(8, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
275
276 conditional_jump(Condition_NE, ".unlock_object_done", true);
277 //jump to dvmJitToExceptionThrown
278 scratchRegs[0] = PhysicalReg_SCRATCH_3;
279 jumpToExceptionThrown(2/*exception number*/);
280 insertLabel(".unlock_object_done", true);
281 ///////////////////////////
282 rPC += 1;
283 return 0;
284 }
285 #undef P_GPR_1
286 #undef P_GPR_2
287
288 #define P_GPR_1 PhysicalReg_EBX
289 #define P_GPR_2 PhysicalReg_ECX
290 #define P_GPR_3 PhysicalReg_EDX /*vA*/
291 //! LOWER bytecode ARRAY_LENGTH
292
293 //! It will use helper function if switch is on
op_array_length()294 int op_array_length() {
295 u2 vA = INST_A(inst);
296 u2 vB = INST_B(inst);
297 ////////////////////
298 //no usage of helper function
299 requestVRFreeDelay(vB,VRDELAY_NULLCHECK); // Request VR delay before transfer to temporary
300 get_virtual_reg(vB, OpndSize_32, 1, false);
301 nullCheck(1, false, 1, vB); //maybe optimized away
302 cancelVRFreeDelayRequest(vB,VRDELAY_NULLCHECK);
303
304 move_mem_to_reg(OpndSize_32, offArrayObject_length, 1, false, 2, false);
305 set_virtual_reg(vA, OpndSize_32, 2, false);
306 ///////////////////////
307 rPC += 1;
308 return 0;
309 }
310 #undef P_GPR_1
311 #undef P_GPR_2
312 #undef P_GPR_3
313
314 #define P_GPR_1 PhysicalReg_EBX
315 #define P_GPR_2 PhysicalReg_ECX
316 #define P_GPR_3 PhysicalReg_ESI
317 //! lower bytecode NEW_INSTANCE
318
319 //! It will use helper function if switch is on
op_new_instance()320 int op_new_instance() {
321 u4 tmp = (u4)FETCH(1);
322 u2 vA = INST_AA(inst);
323 export_pc();
324 /* for trace-based JIT, class is already resolved */
325 ClassObject *classPtr =
326 (currentMethod->clazz->pDvmDex->pResClasses[tmp]);
327 assert(classPtr != NULL);
328 assert(classPtr->status & CLASS_INITIALIZED);
329 /*
330 * If it is going to throw, it should not make to the trace to begin
331 * with. However, Alloc might throw, so we need to genExportPC()
332 */
333 assert((classPtr->accessFlags & (ACC_INTERFACE|ACC_ABSTRACT)) == 0);
334 //prepare to call dvmAllocObject, inputs: resolved class & flag ALLOC_DONT_TRACK
335 load_effective_addr(-8, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
336 /* 1st argument to dvmAllocObject at -8(%esp) */
337 move_imm_to_mem(OpndSize_32, (int)classPtr, 0, PhysicalReg_ESP, true);
338 move_imm_to_mem(OpndSize_32, ALLOC_DONT_TRACK, 4, PhysicalReg_ESP, true);
339 scratchRegs[0] = PhysicalReg_SCRATCH_3;
340 nextVersionOfHardReg(PhysicalReg_EAX, 3); //next version has 3 refs
341 call_dvmAllocObject();
342 load_effective_addr(8, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
343 //return value of dvmAllocObject is in %eax
344 //if return value is null, throw exception
345 compare_imm_reg(OpndSize_32, 0, PhysicalReg_EAX, true);
346 conditional_jump(Condition_NE, ".new_instance_done", true);
347 //jump to dvmJitToExceptionThrown
348 scratchRegs[0] = PhysicalReg_SCRATCH_4;
349 jumpToExceptionThrown(3/*exception number*/);
350 insertLabel(".new_instance_done", true);
351 set_virtual_reg(vA, OpndSize_32, PhysicalReg_EAX, true);
352 rPC += 2;
353 return 0;
354 }
355
356 //! function to initialize a class
357
358 //!INPUT: %eax (class object) %eax is recovered before return
359 //!OUTPUT: none
360 //!CALL: dvmInitClass
361 //!%eax, %esi, %ebx are live through function new_instance_needinit
new_instance_needinit()362 int new_instance_needinit() {
363 insertLabel(".new_instance_needinit", false);
364 load_effective_addr(-8, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
365 move_reg_to_mem(OpndSize_32, PhysicalReg_EAX, true, 0, PhysicalReg_ESP, true);
366 move_reg_to_mem(OpndSize_32, PhysicalReg_EAX, true, 4, PhysicalReg_ESP, true);
367 scratchRegs[0] = PhysicalReg_ECX;
368 call_dvmInitClass();
369 //if return value of dvmInitClass is zero, throw exception
370 compare_imm_reg(OpndSize_32, 0, PhysicalReg_EAX, true);
371 //recover EAX with the class object
372 move_mem_to_reg(OpndSize_32, 4, PhysicalReg_ESP, true, PhysicalReg_EAX, true);
373 load_effective_addr(8, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
374 conditional_jump(Condition_E, "common_exceptionThrown", false);
375 x86_return();
376 return 0;
377 }
378 #undef P_GPR_1
379 #undef P_GPR_2
380 #undef P_GPR_3
381
382 #define P_GPR_1 PhysicalReg_EBX //live through C function, must in callee-saved reg
383 #define P_GPR_2 PhysicalReg_ECX
384 #define P_GPR_3 PhysicalReg_EDX
385 //! lower bytecode NEW_ARRAY
386
387 //! It will use helper function if switch is on
op_new_array()388 int op_new_array() {
389 u4 tmp = (u4)FETCH(1);
390 u2 vA = INST_A(inst); //destination
391 u2 vB = INST_B(inst); //length
392 /////////////////////////
393 // REGS used: %esi, %eax, P_GPR_1, P_GPR_2
394 // CALL class_resolve, dvmAllocArrayByClass
395 export_pc(); //use %edx
396 //check size of the array, if negative, throw exception
397 get_virtual_reg(vB, OpndSize_32, 5, false);
398 compare_imm_reg(OpndSize_32, 0, 5, false);
399 handlePotentialException(Condition_S, Condition_NS,
400 1, "common_errNegArraySize");
401 void *classPtr = (void*)
402 (currentMethod->clazz->pDvmDex->pResClasses[tmp]);
403 assert(classPtr != NULL);
404 //here, class is already resolved, the class object is in %eax
405 //prepare to call dvmAllocArrayByClass with inputs: resolved class, array length, flag ALLOC_DONT_TRACK
406 insertLabel(".new_array_resolved", true);
407 load_effective_addr(-12, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
408 /* 1st argument to dvmAllocArrayByClass at 0(%esp) */
409 move_imm_to_mem(OpndSize_32, (int)classPtr, 0, PhysicalReg_ESP, true);
410 move_reg_to_mem(OpndSize_32, 5, false, 4, PhysicalReg_ESP, true);
411 move_imm_to_mem(OpndSize_32, ALLOC_DONT_TRACK, 8, PhysicalReg_ESP, true);
412 scratchRegs[0] = PhysicalReg_SCRATCH_3;
413 nextVersionOfHardReg(PhysicalReg_EAX, 3); //next version has 3 refs
414 call_dvmAllocArrayByClass();
415 load_effective_addr(12, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
416
417 //the allocated object is in %eax
418 //check whether it is null, throw exception if null
419 compare_imm_reg(OpndSize_32, 0, PhysicalReg_EAX, true);
420 conditional_jump(Condition_NE, ".new_array_done", true);
421 //jump to dvmJitToExceptionThrown
422 scratchRegs[0] = PhysicalReg_SCRATCH_4;
423 jumpToExceptionThrown(2/*exception number*/);
424 insertLabel(".new_array_done", true);
425 set_virtual_reg(vA, OpndSize_32, PhysicalReg_EAX, true);
426 //////////////////////////////////////
427 rPC += 2;
428 return 0;
429 }
430 #undef P_GPR_1
431 #undef P_GPR_2
432 #undef P_GPR_3
433
434 #define P_GPR_1 PhysicalReg_EBX
435 #define P_GPR_2 PhysicalReg_ECX
436 #define P_GPR_3 PhysicalReg_ESI
437 //! common code to lower FILLED_NEW_ARRAY
438
439 //! call: class_resolve call_dvmAllocPrimitiveArray
440 //! exception: filled_new_array_notimpl common_exceptionThrown
common_filled_new_array(u2 length,u4 tmp,bool hasRange)441 int common_filled_new_array(u2 length, u4 tmp, bool hasRange) {
442 ClassObject *classPtr =
443 (currentMethod->clazz->pDvmDex->pResClasses[tmp]);
444 if(classPtr != NULL) ALOGI("FILLED_NEW_ARRAY class %s", classPtr->descriptor);
445 //check whether class is resolved, if yes, jump to resolved
446 //if not, call class_resolve
447 scratchRegs[0] = PhysicalReg_SCRATCH_1; scratchRegs[1] = PhysicalReg_SCRATCH_2;
448 scratchRegs[2] = PhysicalReg_Null; scratchRegs[3] = PhysicalReg_Null;
449 get_res_classes(3, false);
450 move_mem_to_reg(OpndSize_32, tmp*4, 3, false, PhysicalReg_EAX, true);
451 export_pc();
452 compare_imm_reg(OpndSize_32, 0, PhysicalReg_EAX, true); //resolved class
453 conditional_jump(Condition_NE, ".filled_new_array_resolved", true);
454 rememberState(1);
455 move_imm_to_reg(OpndSize_32, tmp, PhysicalReg_EAX, true);
456 call_helper_API(".class_resolve");
457 transferToState(1);
458 //here, class is already resolved
459 insertLabel(".filled_new_array_resolved", true);
460 //check descriptor of the class object, if not implemented, throws exception
461 move_mem_to_reg(OpndSize_32, 24, PhysicalReg_EAX, true, 5, false);
462 //load a single byte of the descriptor
463 movez_mem_to_reg(OpndSize_8, 1, 5, false, 6, false);
464 compare_imm_reg(OpndSize_32, 'I', 6, false);
465 conditional_jump(Condition_E, ".filled_new_array_impl", true);
466 compare_imm_reg(OpndSize_32, 'L', 6, false);
467 conditional_jump(Condition_E, ".filled_new_array_impl", true);
468 compare_imm_reg(OpndSize_32, '[', 6, false);
469 conditional_jump(Condition_NE, ".filled_new_array_notimpl", false);
470
471 insertLabel(".filled_new_array_impl", true);
472 //prepare to call dvmAllocArrayByClass with inputs: classObject, length, flag ALLOC_DONT_TRACK
473 load_effective_addr(-12, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
474 move_imm_to_mem(OpndSize_32, (int)classPtr, 0, PhysicalReg_ESP, true);
475 move_imm_to_mem(OpndSize_32, length, 4, PhysicalReg_ESP, true);
476 move_imm_to_mem(OpndSize_32, ALLOC_DONT_TRACK, 8, PhysicalReg_ESP, true);
477 scratchRegs[0] = PhysicalReg_SCRATCH_3; scratchRegs[1] = PhysicalReg_Null;
478 if(hasRange) {
479 nextVersionOfHardReg(PhysicalReg_EAX, 5+(length >= 1 ? LOOP_COUNT : 0)); //next version
480 }
481 else {
482 nextVersionOfHardReg(PhysicalReg_EAX, 5+length); //next version
483 }
484 call_dvmAllocArrayByClass();
485 load_effective_addr(12, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
486 //return value of dvmAllocPrimitiveArray is in %eax
487 //if the return value is null, throw exception
488 compare_imm_reg(OpndSize_32, 0, PhysicalReg_EAX, true);
489 handlePotentialException(
490 Condition_E, Condition_NE,
491 3, "common_exceptionThrown");
492
493 /* we need to mark the card of the new array, if it's not an int */
494 compare_imm_reg(OpndSize_32, 'I', 6, false);
495 conditional_jump(Condition_E, ".dont_mark_filled_new_array", true);
496
497 // Need to make copy of EAX, because it's used later in op_filled_new_array()
498 move_reg_to_reg(OpndSize_32, PhysicalReg_EAX, true, 6, false);
499
500 markCard_filled(6, false, PhysicalReg_SCRATCH_4, false);
501
502 insertLabel(".dont_mark_filled_new_array", true);
503
504 //return value of bytecode FILLED_NEW_ARRAY is in GLUE structure
505 scratchRegs[0] = PhysicalReg_SCRATCH_4; scratchRegs[1] = PhysicalReg_Null;
506 set_return_value(OpndSize_32, PhysicalReg_EAX, true);
507 return 0;
508 }
509 //! LOWER bytecode FILLED_NEW_ARRAY
510
511 //!
op_filled_new_array()512 int op_filled_new_array() {
513 u2 length = INST_B(inst);
514 u4 tmp = (u4)FETCH(1);
515 u2 v5 = INST_A(inst);
516 u2 vv = FETCH(2);
517 u2 v1 = vv & 0xf;
518 u2 v2 = (vv >> 4) & 0xf;
519 u2 v3 = (vv >> 8) & 0xf;
520 u2 v4 = (vv >> 12) & 0xf;
521 common_filled_new_array(length, tmp, false);
522 if(length >= 1) {
523 //move from virtual register to contents of array object
524 get_virtual_reg(v1, OpndSize_32, 7, false);
525 move_reg_to_mem(OpndSize_32, 7, false, offArrayObject_contents, PhysicalReg_EAX, true);
526 }
527 if(length >= 2) {
528 //move from virtual register to contents of array object
529 get_virtual_reg(v2, OpndSize_32, 8, false);
530 move_reg_to_mem(OpndSize_32, 8, false, offArrayObject_contents+4, PhysicalReg_EAX, true);
531 }
532 if(length >= 3) {
533 //move from virtual register to contents of array object
534 get_virtual_reg(v3, OpndSize_32, 9, false);
535 move_reg_to_mem(OpndSize_32, 9, false, offArrayObject_contents+8, PhysicalReg_EAX, true);
536 }
537 if(length >= 4) {
538 //move from virtual register to contents of array object
539 get_virtual_reg(v4, OpndSize_32, 10, false);
540 move_reg_to_mem(OpndSize_32, 10, false, offArrayObject_contents+12, PhysicalReg_EAX, true);
541 }
542 if(length >= 5) {
543 //move from virtual register to contents of array object
544 get_virtual_reg(v5, OpndSize_32, 11, false);
545 move_reg_to_mem(OpndSize_32, 11, false, offArrayObject_contents+16, PhysicalReg_EAX, true);
546 }
547 rPC += 3;
548 return 0;
549 }
550 //! function to handle the error of array not implemented
551
552 //!
filled_new_array_notimpl()553 int filled_new_array_notimpl() {
554 //two inputs for common_throw:
555 insertLabel(".filled_new_array_notimpl", false);
556 move_imm_to_reg(OpndSize_32, LstrFilledNewArrayNotImpl, PhysicalReg_EAX, true);
557 move_imm_to_reg(OpndSize_32, (int) gDvm.exInternalError, PhysicalReg_ECX, true);
558 unconditional_jump("common_throw", false);
559 return 0;
560 }
561
562 #define P_SCRATCH_1 PhysicalReg_EDX
563 //! LOWER bytecode FILLED_NEW_ARRAY_RANGE
564
565 //!
op_filled_new_array_range()566 int op_filled_new_array_range() {
567 u2 length = INST_AA(inst);
568 u4 tmp = (u4)FETCH(1);
569 u4 vC = (u4)FETCH(2);
570 common_filled_new_array(length, tmp, true/*hasRange*/);
571 //here, %eax points to the array object
572 if(length >= 1) {
573 //dump all virtual registers used by this bytecode to stack, for NCG O1
574 int k;
575 for(k = 0; k < length; k++) {
576 spillVirtualReg(vC+k, LowOpndRegType_gp, true); //will update refCount
577 }
578 //address of the first virtual register that will be moved to the array object
579 load_effective_addr(vC*4, PhysicalReg_FP, true, 7, false); //addr
580 //start address for contents of the array object
581 load_effective_addr(offArrayObject_contents, PhysicalReg_EAX, true, 8, false); //addr
582 //loop counter
583 move_imm_to_reg(OpndSize_32, length-1, 9, false); //counter
584 //start of the loop
585 insertLabel(".filled_new_array_range_loop1", true);
586 rememberState(1);
587 move_mem_to_reg(OpndSize_32, 0, 7, false, 10, false);
588 load_effective_addr(4, 7, false, 7, false);
589 move_reg_to_mem(OpndSize_32, 10, false, 0, 8, false);
590 load_effective_addr(4, 8, false, 8, false);
591 alu_binary_imm_reg(OpndSize_32, sub_opc, 1, 9, false);
592 transferToState(1);
593 //jump back to the loop start
594 conditional_jump(Condition_NS, ".filled_new_array_range_loop1", true);
595 }
596 rPC += 3;
597 return 0;
598 }
599 #undef P_GPR_1
600 #undef P_GPR_2
601 #undef P_GPR_3
602 #undef P_SCRATCH_1
603
604 #define P_GPR_1 PhysicalReg_EBX
605 //! LOWER bytecode FILL_ARRAY_DATA
606
607 //!use 1 GPR and scratch regs (export_pc dvmInterpHandleFillArrayData)
608 //!CALL: dvmInterpHandleFillArrayData
op_fill_array_data()609 int op_fill_array_data() {
610 u2 vA = INST_AA(inst);
611 u4 tmp = (u4)FETCH(1);
612 tmp |= (u4)FETCH(2) << 16;
613 scratchRegs[0] = PhysicalReg_SCRATCH_1;
614 scratchRegs[1] = PhysicalReg_Null;
615 scratchRegs[2] = PhysicalReg_Null; scratchRegs[3] = PhysicalReg_Null;
616 get_virtual_reg(vA, OpndSize_32, 1, false);
617 //prepare to call dvmInterpHandleFillArrayData, input: array object, address of the data
618 load_effective_addr(-8, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
619 move_reg_to_mem(OpndSize_32, 1, false, 0, PhysicalReg_ESP, true);
620 /* 2nd argument to dvmInterpHandleFillArrayData at 4(%esp) */
621 move_imm_to_mem(OpndSize_32, (int)(rPC+tmp), 4, PhysicalReg_ESP, true);
622 call_dvmInterpHandleFillArrayData();
623 load_effective_addr(8, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
624
625 //check return value of dvmInterpHandleFillArrayData, if zero, throw exception
626 compare_imm_reg(OpndSize_32, 0, PhysicalReg_EAX, true);
627 conditional_jump(Condition_NE, ".fill_array_data_done", true);
628 //jump to dvmJitToExceptionThrown
629 scratchRegs[0] = PhysicalReg_SCRATCH_2;
630 jumpToExceptionThrown(2/*exception number*/);
631 insertLabel(".fill_array_data_done", true);
632 rPC += 3;
633 return 0;
634 }
635 #undef P_GPR_1
636
637 #define P_GPR_1 PhysicalReg_EBX
638 //! LOWER bytecode THROW
639
640 //!
op_throw()641 int op_throw() {
642 u2 vA = INST_AA(inst);
643 export_pc();
644 get_virtual_reg(vA, OpndSize_32, 1, false);
645 //null check
646 compare_imm_reg(OpndSize_32, 0, 1, false);
647 conditional_jump(Condition_E, "common_errNullObject", false);
648 //set glue->exception & throw exception
649 scratchRegs[2] = PhysicalReg_Null; scratchRegs[3] = PhysicalReg_Null;
650 scratchRegs[0] = PhysicalReg_SCRATCH_1; scratchRegs[1] = PhysicalReg_SCRATCH_2;
651 set_exception(1, false);
652 unconditional_jump("common_exceptionThrown", false);
653 rPC += 1;
654 return 0;
655 }
656 #undef P_GPR_1
657 #define P_GPR_1 PhysicalReg_EBX
658 //! LOWER bytecode THROW_VERIFICATION_ERROR
659
660 //! op AA, ref@BBBB
op_throw_verification_error()661 int op_throw_verification_error() {
662 u2 vA, vB;
663 vA = INST_AA(inst);
664 vB = FETCH(1);
665
666 export_pc();
667 scratchRegs[0] = PhysicalReg_SCRATCH_1;
668 get_glue_method(1, false);
669
670 load_effective_addr(-12, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
671 move_imm_to_mem(OpndSize_32, vB, 8, PhysicalReg_ESP, true);
672 move_imm_to_mem(OpndSize_32, vA, 4, PhysicalReg_ESP, true);
673 move_reg_to_mem(OpndSize_32, 1, false, 0, PhysicalReg_ESP, true);
674 scratchRegs[0] = PhysicalReg_SCRATCH_2;
675 call_dvmThrowVerificationError();
676 load_effective_addr(12, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
677
678 unconditional_jump("common_exceptionThrown", false);
679 rPC += 2;
680 return 0;
681 }
682 #undef P_GPR_1
683