1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 */ 18 package org.apache.bcel.generic; 19 20 /** 21 * SWITCH - Branch depending on int value, generates either LOOKUPSWITCH or 22 * TABLESWITCH instruction, depending on whether the match values (int[]) can be 23 * sorted with no gaps between the numbers. 24 * 25 * @version $Id$ 26 */ 27 public final class SWITCH implements CompoundInstruction { 28 29 private int[] match; 30 private InstructionHandle[] targets; 31 private Select instruction; 32 private int match_length; 33 34 35 /** 36 * Template for switch() constructs. If the match array can be 37 * sorted in ascending order with gaps no larger than max_gap 38 * between the numbers, a TABLESWITCH instruction is generated, and 39 * a LOOKUPSWITCH otherwise. The former may be more efficient, but 40 * needs more space. 41 * 42 * Note, that the key array always will be sorted, though we leave 43 * the original arrays unaltered. 44 * 45 * @param match array of match values (case 2: ... case 7: ..., etc.) 46 * @param targets the instructions to be branched to for each case 47 * @param target the default target 48 * @param max_gap maximum gap that may between case branches 49 */ SWITCH(final int[] match, final InstructionHandle[] targets, final InstructionHandle target, final int max_gap)50 public SWITCH(final int[] match, final InstructionHandle[] targets, final InstructionHandle target, final int max_gap) { 51 this.match = match.clone(); 52 this.targets = targets.clone(); 53 if ((match_length = match.length) < 2) { 54 instruction = new TABLESWITCH(match, targets, target); 55 } else { 56 sort(0, match_length - 1); 57 if (matchIsOrdered(max_gap)) { 58 fillup(max_gap, target); 59 instruction = new TABLESWITCH(this.match, this.targets, target); 60 } else { 61 instruction = new LOOKUPSWITCH(this.match, this.targets, target); 62 } 63 } 64 } 65 66 SWITCH(final int[] match, final InstructionHandle[] targets, final InstructionHandle target)67 public SWITCH(final int[] match, final InstructionHandle[] targets, final InstructionHandle target) { 68 this(match, targets, target, 1); 69 } 70 71 fillup( final int max_gap, final InstructionHandle target )72 private void fillup( final int max_gap, final InstructionHandle target ) { 73 final int max_size = match_length + match_length * max_gap; 74 final int[] m_vec = new int[max_size]; 75 final InstructionHandle[] t_vec = new InstructionHandle[max_size]; 76 int count = 1; 77 m_vec[0] = match[0]; 78 t_vec[0] = targets[0]; 79 for (int i = 1; i < match_length; i++) { 80 final int prev = match[i - 1]; 81 final int gap = match[i] - prev; 82 for (int j = 1; j < gap; j++) { 83 m_vec[count] = prev + j; 84 t_vec[count] = target; 85 count++; 86 } 87 m_vec[count] = match[i]; 88 t_vec[count] = targets[i]; 89 count++; 90 } 91 match = new int[count]; 92 targets = new InstructionHandle[count]; 93 System.arraycopy(m_vec, 0, match, 0, count); 94 System.arraycopy(t_vec, 0, targets, 0, count); 95 } 96 97 98 /** 99 * Sort match and targets array with QuickSort. 100 */ sort( final int l, final int r )101 private void sort( final int l, final int r ) { 102 int i = l; 103 int j = r; 104 int h; 105 final int m = match[(l + r) / 2]; 106 InstructionHandle h2; 107 do { 108 while (match[i] < m) { 109 i++; 110 } 111 while (m < match[j]) { 112 j--; 113 } 114 if (i <= j) { 115 h = match[i]; 116 match[i] = match[j]; 117 match[j] = h; // Swap elements 118 h2 = targets[i]; 119 targets[i] = targets[j]; 120 targets[j] = h2; // Swap instructions, too 121 i++; 122 j--; 123 } 124 } while (i <= j); 125 if (l < j) { 126 sort(l, j); 127 } 128 if (i < r) { 129 sort(i, r); 130 } 131 } 132 133 134 /** 135 * @return match is sorted in ascending order with no gap bigger than max_gap? 136 */ matchIsOrdered( final int max_gap )137 private boolean matchIsOrdered( final int max_gap ) { 138 for (int i = 1; i < match_length; i++) { 139 if (match[i] - match[i - 1] > max_gap) { 140 return false; 141 } 142 } 143 return true; 144 } 145 146 147 @Override getInstructionList()148 public final InstructionList getInstructionList() { 149 return new InstructionList(instruction); 150 } 151 152 getInstruction()153 public final Instruction getInstruction() { 154 return instruction; 155 } 156 } 157