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