blob: 4eccf0481420b13f878ecc53789236ed068c4740 [file] [log] [blame]
buzbeee3acd072012-02-25 17:03:10 -08001/*
2 * Copyright (C) 2011 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
17namespace art {
18
buzbee31a4a6f2012-02-28 15:36:15 -080019void setMemRefType(LIR* lir, bool isLoad, int memType)
20{
21 u8 *maskPtr;
22 u8 mask = ENCODE_MEM;;
23 DCHECK(EncodingMap[lir->opcode].flags & (IS_LOAD | IS_STORE));
24 if (isLoad) {
25 maskPtr = &lir->useMask;
26 } else {
27 maskPtr = &lir->defMask;
28 }
29 /* Clear out the memref flags */
30 *maskPtr &= ~mask;
31 /* ..and then add back the one we need */
32 switch(memType) {
33 case kLiteral:
34 DCHECK(isLoad);
35 *maskPtr |= ENCODE_LITERAL;
36 break;
37 case kDalvikReg:
38 *maskPtr |= ENCODE_DALVIK_REG;
39 break;
40 case kHeapRef:
41 *maskPtr |= ENCODE_HEAP_REF;
42 break;
43 case kMustNotAlias:
44 /* Currently only loads can be marked as kMustNotAlias */
45 DCHECK(!(EncodingMap[lir->opcode].flags & IS_STORE));
46 *maskPtr |= ENCODE_MUST_NOT_ALIAS;
47 break;
48 default:
49 LOG(FATAL) << "Oat: invalid memref kind - " << memType;
50 }
51}
52
53/*
54 * Mark load/store instructions that access Dalvik registers through r5FP +
55 * offset.
56 */
57void annotateDalvikRegAccess(LIR* lir, int regId, bool isLoad)
58{
59 setMemRefType(lir, isLoad, kDalvikReg);
60
61 /*
62 * Store the Dalvik register id in aliasInfo. Mark he MSB if it is a 64-bit
63 * access.
64 */
65 lir->aliasInfo = regId;
66 if (DOUBLEREG(lir->operands[0])) {
67 lir->aliasInfo |= 0x80000000;
68 }
69}
70
71/*
72 * Decode the register id.
73 */
74inline u8 getRegMaskCommon(int reg)
75{
76 u8 seed;
77 int shift;
78 int regId = reg & 0x1f;
79
80 /*
81 * Each double register is equal to a pair of single-precision FP registers
82 */
83 seed = DOUBLEREG(reg) ? 3 : 1;
84 /* FP register starts at bit position 16 */
85 shift = FPREG(reg) ? kFPReg0 : 0;
86 /* Expand the double register id into single offset */
87 shift += regId;
88 return (seed << shift);
89}
90
91/*
92 * Mark the corresponding bit(s).
93 */
94inline void setupRegMask(u8* mask, int reg)
95{
96 *mask |= getRegMaskCommon(reg);
97}
98
99/*
100 * Set up the proper fields in the resource mask
101 */
102void setupResourceMasks(LIR* lir)
103{
104 int opcode = lir->opcode;
105 int flags;
106
107 if (opcode <= 0) {
108 lir->useMask = lir->defMask = 0;
109 return;
110 }
111
112 flags = EncodingMap[lir->opcode].flags;
113
114 if (flags & NEEDS_FIXUP) {
115 lir->flags.pcRelFixup = true;
116 }
117
118 /* Set up the mask for resources that are updated */
119 if (flags & (IS_LOAD | IS_STORE)) {
120 /* Default to heap - will catch specialized classes later */
121 setMemRefType(lir, flags & IS_LOAD, kHeapRef);
122 }
123
124 /*
125 * Conservatively assume the branch here will call out a function that in
126 * turn will trash everything.
127 */
128 if (flags & IS_BRANCH) {
129 lir->defMask = lir->useMask = ENCODE_ALL;
130 return;
131 }
132
133 if (flags & REG_DEF0) {
134 setupRegMask(&lir->defMask, lir->operands[0]);
135 }
136
137 if (flags & REG_DEF1) {
138 setupRegMask(&lir->defMask, lir->operands[1]);
139 }
140
141 if (flags & REG_DEF_SP) {
142 lir->defMask |= ENCODE_REG_SP;
143 }
144
145 if (flags & REG_DEF_LR) {
146 lir->defMask |= ENCODE_REG_LR;
147 }
148
149 if (flags & REG_DEF_LIST0) {
150 lir->defMask |= ENCODE_REG_LIST(lir->operands[0]);
151 }
152
153 if (flags & REG_DEF_LIST1) {
154 lir->defMask |= ENCODE_REG_LIST(lir->operands[1]);
155 }
156
157 if (flags & REG_DEF_FPCS_LIST0) {
158 lir->defMask |= ENCODE_REG_FPCS_LIST(lir->operands[0]);
159 }
160
161 if (flags & REG_DEF_FPCS_LIST2) {
162 for (int i = 0; i < lir->operands[2]; i++) {
163 setupRegMask(&lir->defMask, lir->operands[1] + i);
164 }
165 }
166
167 if (flags & SETS_CCODES) {
168 lir->defMask |= ENCODE_CCODE;
169 }
170
171#if defined(TARGET_ARM)
172 /* Conservatively treat the IT block */
173 if (flags & IS_IT) {
174 lir->defMask = ENCODE_ALL;
175 }
176#endif
177
178 if (flags & (REG_USE0 | REG_USE1 | REG_USE2 | REG_USE3)) {
179 int i;
180
181 for (i = 0; i < 4; i++) {
182 if (flags & (1 << (kRegUse0 + i))) {
183 setupRegMask(&lir->useMask, lir->operands[i]);
184 }
185 }
186 }
187
188 if (flags & REG_USE_PC) {
189 lir->useMask |= ENCODE_REG_PC;
190 }
191
192 if (flags & REG_USE_SP) {
193 lir->useMask |= ENCODE_REG_SP;
194 }
195
196 if (flags & REG_USE_LIST0) {
197 lir->useMask |= ENCODE_REG_LIST(lir->operands[0]);
198 }
199
200 if (flags & REG_USE_LIST1) {
201 lir->useMask |= ENCODE_REG_LIST(lir->operands[1]);
202 }
203
204 if (flags & REG_USE_FPCS_LIST0) {
205 lir->useMask |= ENCODE_REG_FPCS_LIST(lir->operands[0]);
206 }
207
208 if (flags & REG_USE_FPCS_LIST2) {
209 for (int i = 0; i < lir->operands[2]; i++) {
210 setupRegMask(&lir->useMask, lir->operands[1] + i);
211 }
212 }
213
214 if (flags & USES_CCODES) {
215 lir->useMask |= ENCODE_CCODE;
216 }
217
218#if defined(TARGET_ARM)
219 /* Fixup for kThumbPush/lr and kThumbPop/pc */
220 if (opcode == kThumbPush || opcode == kThumbPop) {
221 u8 r8Mask = getRegMaskCommon(r8);
222 if ((opcode == kThumbPush) && (lir->useMask & r8Mask)) {
223 lir->useMask &= ~r8Mask;
224 lir->useMask |= ENCODE_REG_LR;
225 } else if ((opcode == kThumbPop) && (lir->defMask & r8Mask)) {
226 lir->defMask &= ~r8Mask;
227 lir->defMask |= ENCODE_REG_PC;
228 }
229 }
230#endif
231}
232
233/*
234 * The following are building blocks to construct low-level IRs with 0 - 4
235 * operands.
236 */
237LIR* newLIR0(CompilationUnit* cUnit, ArmOpcode opcode)
238{
239 LIR* insn = (LIR* ) oatNew(cUnit, sizeof(LIR), true, kAllocLIR);
240 DCHECK(isPseudoOpcode(opcode) || (EncodingMap[opcode].flags & NO_OPERAND));
241 insn->opcode = opcode;
242 setupResourceMasks(insn);
243 insn->dalvikOffset = cUnit->currentDalvikOffset;
244 oatAppendLIR(cUnit, (LIR*) insn);
245 return insn;
246}
247
248LIR* newLIR1(CompilationUnit* cUnit, ArmOpcode opcode,
249 int dest)
250{
251 LIR* insn = (LIR* ) oatNew(cUnit, sizeof(LIR), true, kAllocLIR);
252 DCHECK(isPseudoOpcode(opcode) || (EncodingMap[opcode].flags & IS_UNARY_OP));
253 insn->opcode = opcode;
254 insn->operands[0] = dest;
255 setupResourceMasks(insn);
256 insn->dalvikOffset = cUnit->currentDalvikOffset;
257 oatAppendLIR(cUnit, (LIR*) insn);
258 return insn;
259}
260
261LIR* newLIR2(CompilationUnit* cUnit, ArmOpcode opcode,
262 int dest, int src1)
263{
264 LIR* insn = (LIR* ) oatNew(cUnit, sizeof(LIR), true, kAllocLIR);
265 DCHECK(isPseudoOpcode(opcode) ||
266 (EncodingMap[opcode].flags & IS_BINARY_OP));
267 insn->opcode = opcode;
268 insn->operands[0] = dest;
269 insn->operands[1] = src1;
270 setupResourceMasks(insn);
271 insn->dalvikOffset = cUnit->currentDalvikOffset;
272 oatAppendLIR(cUnit, (LIR*) insn);
273 return insn;
274}
275
276LIR* newLIR3(CompilationUnit* cUnit, ArmOpcode opcode,
277 int dest, int src1, int src2)
278{
279 LIR* insn = (LIR* ) oatNew(cUnit, sizeof(LIR), true, kAllocLIR);
280 DCHECK(isPseudoOpcode(opcode) ||
281 (EncodingMap[opcode].flags & IS_TERTIARY_OP))
282 << (int)opcode << " "
283 << PrettyMethod(cUnit->method_idx, *cUnit->dex_file) << " "
284 << cUnit->currentDalvikOffset;
285 insn->opcode = opcode;
286 insn->operands[0] = dest;
287 insn->operands[1] = src1;
288 insn->operands[2] = src2;
289 setupResourceMasks(insn);
290 insn->dalvikOffset = cUnit->currentDalvikOffset;
291 oatAppendLIR(cUnit, (LIR*) insn);
292 return insn;
293}
294
295#if defined(TARGET_ARM)
296LIR* newLIR4(CompilationUnit* cUnit, ArmOpcode opcode,
297 int dest, int src1, int src2, int info)
298{
299 LIR* insn = (LIR* ) oatNew(cUnit, sizeof(LIR), true, kAllocLIR);
300 DCHECK(isPseudoOpcode(opcode) ||
301 (EncodingMap[opcode].flags & IS_QUAD_OP));
302 insn->opcode = opcode;
303 insn->operands[0] = dest;
304 insn->operands[1] = src1;
305 insn->operands[2] = src2;
306 insn->operands[3] = info;
307 setupResourceMasks(insn);
308 insn->dalvikOffset = cUnit->currentDalvikOffset;
309 oatAppendLIR(cUnit, (LIR*) insn);
310 return insn;
311}
312#endif
313
314/*
315 * Search the existing constants in the literal pool for an exact or close match
316 * within specified delta (greater or equal to 0).
317 */
318LIR* scanLiteralPool(LIR* dataTarget, int value, unsigned int delta)
319{
320 while (dataTarget) {
321 if (((unsigned) (value - ((LIR* ) dataTarget)->operands[0])) <=
322 delta)
323 return (LIR* ) dataTarget;
324 dataTarget = dataTarget->next;
325 }
326 return NULL;
327}
328
329/* Search the existing constants in the literal pool for an exact wide match */
330LIR* scanLiteralPoolWide(LIR* dataTarget, int valLo, int valHi)
331{
332 bool loMatch = false;
333 LIR* loTarget = NULL;
334 while (dataTarget) {
335 if (loMatch && (((LIR*)dataTarget)->operands[0] == valHi)) {
336 return (LIR*)loTarget;
337 }
338 loMatch = false;
339 if (((LIR*)dataTarget)->operands[0] == valLo) {
340 loMatch = true;
341 loTarget = dataTarget;
342 }
343 dataTarget = dataTarget->next;
344 }
345 return NULL;
346}
347
348/*
349 * The following are building blocks to insert constants into the pool or
350 * instruction streams.
351 */
352
353/* Add a 32-bit constant either in the constant pool or mixed with code */
354LIR* addWordData(CompilationUnit* cUnit, LIR* *constantListP,
355 int value)
356{
357 /* Add the constant to the literal pool */
358 if (constantListP) {
359 LIR* newValue = (LIR* ) oatNew(cUnit, sizeof(LIR), true,
360 kAllocData);
361 newValue->operands[0] = value;
362 newValue->next = *constantListP;
363 *constantListP = (LIR*) newValue;
364 return newValue;
365 } else {
366 /* Add the constant in the middle of code stream */
367 newLIR1(cUnit, kArm16BitData, (value & 0xffff));
368 newLIR1(cUnit, kArm16BitData, (value >> 16));
369 }
370 return NULL;
371}
372
373/* Add a 64-bit constant to the constant pool or mixed with code */
374LIR* addWideData(CompilationUnit* cUnit, LIR* *constantListP,
375 int valLo, int valHi)
376{
377 LIR* res;
378 //FIXME: hard-coded little endian, need BE variant
379 if (constantListP == NULL) {
380 res = addWordData(cUnit, NULL, valLo);
381 addWordData(cUnit, NULL, valHi);
382 } else {
383 // Insert high word into list first
384 addWordData(cUnit, constantListP, valHi);
385 res = addWordData(cUnit, constantListP, valLo);
386 }
387 return res;
388}
389
390void pushWord(std::vector<uint16_t>&buf, int data) {
buzbeee3acd072012-02-25 17:03:10 -0800391 buf.push_back( data & 0xffff);
392 buf.push_back( (data >> 16) & 0xffff);
393}
394
395void alignBuffer(std::vector<uint16_t>&buf, size_t offset) {
396 while (buf.size() < (offset/2))
397 buf.push_back(0);
398}
399
400/* Write the literal pool to the output stream */
buzbee31a4a6f2012-02-28 15:36:15 -0800401void installLiteralPools(CompilationUnit* cUnit)
buzbeee3acd072012-02-25 17:03:10 -0800402{
403 alignBuffer(cUnit->codeBuffer, cUnit->dataOffset);
buzbee31a4a6f2012-02-28 15:36:15 -0800404 LIR* dataLIR = (LIR*) cUnit->literalList;
buzbeee3acd072012-02-25 17:03:10 -0800405 while (dataLIR != NULL) {
406 pushWord(cUnit->codeBuffer, dataLIR->operands[0]);
407 dataLIR = NEXT_LIR(dataLIR);
408 }
409}
410
411/* Write the switch tables to the output stream */
buzbee31a4a6f2012-02-28 15:36:15 -0800412void installSwitchTables(CompilationUnit* cUnit)
buzbeee3acd072012-02-25 17:03:10 -0800413{
414 GrowableListIterator iterator;
415 oatGrowableListIteratorInit(&cUnit->switchTables, &iterator);
416 while (true) {
417 SwitchTable* tabRec = (SwitchTable *) oatGrowableListIteratorNext(
418 &iterator);
419 if (tabRec == NULL) break;
420 alignBuffer(cUnit->codeBuffer, tabRec->offset);
buzbee31a4a6f2012-02-28 15:36:15 -0800421 int bxOffset = tabRec->bxInst->offset + 4;
buzbeee3acd072012-02-25 17:03:10 -0800422 if (cUnit->printMe) {
423 LOG(INFO) << "Switch table for offset 0x" << std::hex << bxOffset;
424 }
425 if (tabRec->table[0] == kSparseSwitchSignature) {
426 int* keys = (int*)&(tabRec->table[2]);
427 for (int elems = 0; elems < tabRec->table[1]; elems++) {
buzbee31a4a6f2012-02-28 15:36:15 -0800428 int disp = tabRec->targets[elems]->offset - bxOffset;
buzbeee3acd072012-02-25 17:03:10 -0800429 if (cUnit->printMe) {
430 LOG(INFO) << " Case[" << elems << "] key: 0x" <<
431 std::hex << keys[elems] << ", disp: 0x" <<
432 std::hex << disp;
433 }
434 pushWord(cUnit->codeBuffer, keys[elems]);
435 pushWord(cUnit->codeBuffer,
buzbee31a4a6f2012-02-28 15:36:15 -0800436 tabRec->targets[elems]->offset - bxOffset);
buzbeee3acd072012-02-25 17:03:10 -0800437 }
438 } else {
439 DCHECK_EQ(tabRec->table[0], kPackedSwitchSignature);
440 for (int elems = 0; elems < tabRec->table[1]; elems++) {
buzbee31a4a6f2012-02-28 15:36:15 -0800441 int disp = tabRec->targets[elems]->offset - bxOffset;
buzbeee3acd072012-02-25 17:03:10 -0800442 if (cUnit->printMe) {
443 LOG(INFO) << " Case[" << elems << "] disp: 0x" <<
444 std::hex << disp;
445 }
446 pushWord(cUnit->codeBuffer,
buzbee31a4a6f2012-02-28 15:36:15 -0800447 tabRec->targets[elems]->offset - bxOffset);
buzbeee3acd072012-02-25 17:03:10 -0800448 }
449 }
450 }
451}
452
453/* Write the fill array dta to the output stream */
buzbee31a4a6f2012-02-28 15:36:15 -0800454void installFillArrayData(CompilationUnit* cUnit)
buzbeee3acd072012-02-25 17:03:10 -0800455{
456 GrowableListIterator iterator;
457 oatGrowableListIteratorInit(&cUnit->fillArrayData, &iterator);
458 while (true) {
459 FillArrayData *tabRec = (FillArrayData *) oatGrowableListIteratorNext(
460 &iterator);
461 if (tabRec == NULL) break;
462 alignBuffer(cUnit->codeBuffer, tabRec->offset);
463 for (int i = 0; i < ((tabRec->size + 1) / 2) ; i++) {
464 cUnit->codeBuffer.push_back( tabRec->table[i]);
465 }
466 }
467}
468
buzbee31a4a6f2012-02-28 15:36:15 -0800469int assignLiteralOffsetCommon(LIR* lir, int offset)
buzbeee3acd072012-02-25 17:03:10 -0800470{
471 for (;lir != NULL; lir = lir->next) {
472 lir->offset = offset;
473 offset += 4;
474 }
475 return offset;
476}
477
buzbee31a4a6f2012-02-28 15:36:15 -0800478void createMappingTable(CompilationUnit* cUnit)
buzbeee3acd072012-02-25 17:03:10 -0800479{
buzbee31a4a6f2012-02-28 15:36:15 -0800480 LIR* tgtLIR;
buzbeee3acd072012-02-25 17:03:10 -0800481 int currentDalvikOffset = -1;
482
buzbee31a4a6f2012-02-28 15:36:15 -0800483 for (tgtLIR = (LIR *) cUnit->firstLIRInsn;
buzbeee3acd072012-02-25 17:03:10 -0800484 tgtLIR;
485 tgtLIR = NEXT_LIR(tgtLIR)) {
486 if ((tgtLIR->opcode >= 0) && !tgtLIR->flags.isNop &&
buzbee31a4a6f2012-02-28 15:36:15 -0800487 (currentDalvikOffset != tgtLIR->dalvikOffset)) {
buzbeee3acd072012-02-25 17:03:10 -0800488 // Changed - need to emit a record
buzbee31a4a6f2012-02-28 15:36:15 -0800489 cUnit->mappingTable.push_back(tgtLIR->offset);
490 cUnit->mappingTable.push_back(tgtLIR->dalvikOffset);
491 currentDalvikOffset = tgtLIR->dalvikOffset;
buzbeee3acd072012-02-25 17:03:10 -0800492 }
493 }
494}
495
496/* Determine the offset of each literal field */
buzbee31a4a6f2012-02-28 15:36:15 -0800497int assignLiteralOffset(CompilationUnit* cUnit, int offset)
buzbeee3acd072012-02-25 17:03:10 -0800498{
499 offset = assignLiteralOffsetCommon(cUnit->literalList, offset);
500 return offset;
501}
502
buzbee31a4a6f2012-02-28 15:36:15 -0800503int assignSwitchTablesOffset(CompilationUnit* cUnit, int offset)
buzbeee3acd072012-02-25 17:03:10 -0800504{
505 GrowableListIterator iterator;
506 oatGrowableListIteratorInit(&cUnit->switchTables, &iterator);
507 while (true) {
508 SwitchTable *tabRec = (SwitchTable *) oatGrowableListIteratorNext(
509 &iterator);
510 if (tabRec == NULL) break;
511 tabRec->offset = offset;
512 if (tabRec->table[0] == kSparseSwitchSignature) {
513 offset += tabRec->table[1] * (sizeof(int) * 2);
514 } else {
515 DCHECK_EQ(tabRec->table[0], kPackedSwitchSignature);
516 offset += tabRec->table[1] * sizeof(int);
517 }
518 }
519 return offset;
520}
521
buzbee31a4a6f2012-02-28 15:36:15 -0800522int assignFillArrayDataOffset(CompilationUnit* cUnit, int offset)
buzbeee3acd072012-02-25 17:03:10 -0800523{
524 GrowableListIterator iterator;
525 oatGrowableListIteratorInit(&cUnit->fillArrayData, &iterator);
526 while (true) {
527 FillArrayData *tabRec = (FillArrayData *) oatGrowableListIteratorNext(
528 &iterator);
529 if (tabRec == NULL) break;
530 tabRec->offset = offset;
531 offset += tabRec->size;
532 // word align
533 offset = (offset + 3) & ~3;
534 }
535 return offset;
536}
537
538/*
539 * Walk the compilation unit and assign offsets to instructions
540 * and literals and compute the total size of the compiled unit.
541 */
542void oatAssignOffsets(CompilationUnit* cUnit)
543{
544 int offset = oatAssignInsnOffsets(cUnit);
545
546 /* Const values have to be word aligned */
547 offset = (offset + 3) & ~3;
548
549 /* Set up offsets for literals */
550 cUnit->dataOffset = offset;
551
552 offset = assignLiteralOffset(cUnit, offset);
553
554 offset = assignSwitchTablesOffset(cUnit, offset);
555
556 offset = assignFillArrayDataOffset(cUnit, offset);
557
558 cUnit->totalSize = offset;
559}
560
561/*
562 * Go over each instruction in the list and calculate the offset from the top
563 * before sending them off to the assembler. If out-of-range branch distance is
564 * seen rearrange the instructions a bit to correct it.
565 */
566void oatAssembleLIR(CompilationUnit* cUnit)
567{
568 oatAssignOffsets(cUnit);
569 /*
570 * Assemble here. Note that we generate code with optimistic assumptions
571 * and if found now to work, we'll have to redo the sequence and retry.
572 */
573
574 while (true) {
575 AssemblerStatus res = oatAssembleInstructions(cUnit, 0);
576 if (res == kSuccess) {
577 break;
578 } else {
579 cUnit->assemblerRetries++;
580 if (cUnit->assemblerRetries > MAX_ASSEMBLER_RETRIES) {
581 LOG(FATAL) << "Assembler error - too many retries";
582 }
583 // Redo offsets and try again
584 oatAssignOffsets(cUnit);
585 cUnit->codeBuffer.clear();
586 }
587 }
588
589 // Install literals
590 installLiteralPools(cUnit);
591
592 // Install switch tables
593 installSwitchTables(cUnit);
594
595 // Install fill array data
596 installFillArrayData(cUnit);
597
598 /*
599 * Create the mapping table
600 */
601 createMappingTable(cUnit);
602}
603
buzbee31a4a6f2012-02-28 15:36:15 -0800604/*
605 * Insert a kPseudoCaseLabel at the beginning of the Dalvik
606 * offset vaddr. This label will be used to fix up the case
607 * branch table during the assembly phase. Be sure to set
608 * all resource flags on this to prevent code motion across
609 * target boundaries. KeyVal is just there for debugging.
610 */
611LIR* insertCaseLabel(CompilationUnit* cUnit, int vaddr, int keyVal)
612{
613 std::map<unsigned int, LIR*>::iterator it;
614 it = cUnit->boundaryMap.find(vaddr);
615 if (it == cUnit->boundaryMap.end()) {
616 LOG(FATAL) << "Error: didn't find vaddr 0x" << std::hex << vaddr;
617 }
618 LIR* newLabel = (LIR*)oatNew(cUnit, sizeof(LIR), true, kAllocLIR);
619 newLabel->dalvikOffset = vaddr;
620 newLabel->opcode = kPseudoCaseLabel;
621 newLabel->operands[0] = keyVal;
622 oatInsertLIRAfter(it->second, (LIR*)newLabel);
623 return newLabel;
624}
625
626void markPackedCaseLabels(CompilationUnit* cUnit, SwitchTable *tabRec)
627{
628 const u2* table = tabRec->table;
629 int baseVaddr = tabRec->vaddr;
630 int *targets = (int*)&table[4];
631 int entries = table[1];
632 int lowKey = s4FromSwitchData(&table[2]);
633 for (int i = 0; i < entries; i++) {
634 tabRec->targets[i] = insertCaseLabel(cUnit, baseVaddr + targets[i],
635 i + lowKey);
636 }
637}
638
639void markSparseCaseLabels(CompilationUnit* cUnit, SwitchTable *tabRec)
640{
641 const u2* table = tabRec->table;
642 int baseVaddr = tabRec->vaddr;
643 int entries = table[1];
644 int* keys = (int*)&table[2];
645 int* targets = &keys[entries];
646 for (int i = 0; i < entries; i++) {
647 tabRec->targets[i] = insertCaseLabel(cUnit, baseVaddr + targets[i],
648 keys[i]);
649 }
650}
651
652void oatProcessSwitchTables(CompilationUnit* cUnit)
653{
654 GrowableListIterator iterator;
655 oatGrowableListIteratorInit(&cUnit->switchTables, &iterator);
656 while (true) {
657 SwitchTable *tabRec = (SwitchTable *) oatGrowableListIteratorNext(
658 &iterator);
659 if (tabRec == NULL) break;
660 if (tabRec->table[0] == kPackedSwitchSignature)
661 markPackedCaseLabels(cUnit, tabRec);
662 else if (tabRec->table[0] == kSparseSwitchSignature)
663 markSparseCaseLabels(cUnit, tabRec);
664 else {
665 LOG(FATAL) << "Invalid switch table";
666 }
667 }
668}
669
670//FIXME: Do we have endian issues here?
671
672void dumpSparseSwitchTable(const u2* table)
673 /*
674 * Sparse switch data format:
675 * ushort ident = 0x0200 magic value
676 * ushort size number of entries in the table; > 0
677 * int keys[size] keys, sorted low-to-high; 32-bit aligned
678 * int targets[size] branch targets, relative to switch opcode
679 *
680 * Total size is (2+size*4) 16-bit code units.
681 */
682{
683 u2 ident = table[0];
684 int entries = table[1];
685 int* keys = (int*)&table[2];
686 int* targets = &keys[entries];
687 LOG(INFO) << "Sparse switch table - ident:0x" << std::hex << ident <<
688 ", entries: " << std::dec << entries;
689 for (int i = 0; i < entries; i++) {
690 LOG(INFO) << " Key[" << keys[i] << "] -> 0x" << std::hex <<
691 targets[i];
692 }
693}
694
695void dumpPackedSwitchTable(const u2* table)
696 /*
697 * Packed switch data format:
698 * ushort ident = 0x0100 magic value
699 * ushort size number of entries in the table
700 * int first_key first (and lowest) switch case value
701 * int targets[size] branch targets, relative to switch opcode
702 *
703 * Total size is (4+size*2) 16-bit code units.
704 */
705{
706 u2 ident = table[0];
707 int* targets = (int*)&table[4];
708 int entries = table[1];
709 int lowKey = s4FromSwitchData(&table[2]);
710 LOG(INFO) << "Packed switch table - ident:0x" << std::hex << ident <<
711 ", entries: " << std::dec << entries << ", lowKey: " << lowKey;
712 for (int i = 0; i < entries; i++) {
713 LOG(INFO) << " Key[" << (i + lowKey) << "] -> 0x" << std::hex <<
714 targets[i];
715 }
716}
buzbeee3acd072012-02-25 17:03:10 -0800717
718
719} // namespace art