View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   https://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.commons.compress.harmony.unpack200.bytecode.forms;
20  
21  import java.util.Arrays;
22  
23  import org.apache.commons.compress.harmony.unpack200.bytecode.ByteCode;
24  import org.apache.commons.compress.harmony.unpack200.bytecode.OperandManager;
25  
26  /**
27   * Lookup switch instruction form.
28   */
29  public class LookupSwitchForm extends SwitchForm {
30  
31      /**
32       * Constructs a new instance with the specified opcode, name, operandType and rewrite.
33       *
34       * @param opcode  index corresponding to the opcode's value.
35       * @param name    String printable name of the opcode.
36       */
37      public LookupSwitchForm(final int opcode, final String name) {
38          super(opcode, name);
39      }
40  
41      @Override
42      public void setByteCodeOperands(final ByteCode byteCode, final OperandManager operandManager, final int codeLength) {
43          final int caseCount = operandManager.nextCaseCount();
44          final int defaultPc = operandManager.nextLabel();
45          final int[] caseValues = new int[caseCount];
46          Arrays.setAll(caseValues, i -> operandManager.nextCaseValues());
47          final int[] casePcs = new int[caseCount];
48          Arrays.setAll(casePcs, i -> operandManager.nextLabel());
49  
50          final int[] labelsArray = new int[caseCount + 1];
51          labelsArray[0] = defaultPc;
52          System.arraycopy(casePcs, 0, labelsArray, 1, caseCount + 1 - 1);
53          byteCode.setByteCodeTargets(labelsArray);
54  
55          // All this gets dumped into the rewrite bytes of the
56          // poor bytecode.
57  
58          // Unlike most byte codes, the LookupSwitch is a
59          // variable-sized bytecode. Because of this, the
60          // rewrite array has to be defined here individually
61          // for each bytecode, rather than in the ByteCodeForm
62          // class.
63  
64          // First, there's the bytecode. Then there are 0-3
65          // bytes of padding so that the first (default)
66          // label is on a 4-byte offset.
67          final int padLength = 3 - codeLength % 4;
68          final int rewriteSize = 1 + padLength + 4 // defaultbytes
69                  + 4 // npairs
70                  + 4 * caseValues.length + 4 * casePcs.length;
71  
72          final int[] newRewrite = new int[rewriteSize];
73          int rewriteIndex = 0;
74  
75          // Fill in what we can now
76          // opcode
77          newRewrite[rewriteIndex++] = byteCode.getOpcode();
78  
79          // padding
80          for (int index = 0; index < padLength; index++) {
81              newRewrite[rewriteIndex++] = 0;
82          }
83  
84          // defaultbyte
85          // This gets overwritten by fixUpByteCodeTargets
86          newRewrite[rewriteIndex++] = -1;
87          newRewrite[rewriteIndex++] = -1;
88          newRewrite[rewriteIndex++] = -1;
89          newRewrite[rewriteIndex++] = -1;
90  
91          // npairs
92          final int npairsIndex = rewriteIndex;
93          setRewrite4Bytes(caseValues.length, npairsIndex, newRewrite);
94          rewriteIndex += 4;
95  
96          // match-offset pairs
97          // The caseValues aren't overwritten, but the
98          // casePcs will get overwritten by fixUpByteCodeTargets
99          for (final int caseValue : caseValues) {
100             // match
101             setRewrite4Bytes(caseValue, rewriteIndex, newRewrite);
102             rewriteIndex += 4;
103             // offset
104             newRewrite[rewriteIndex++] = -1;
105             newRewrite[rewriteIndex++] = -1;
106             newRewrite[rewriteIndex++] = -1;
107             newRewrite[rewriteIndex++] = -1;
108         }
109         byteCode.setRewrite(newRewrite);
110     }
111 }