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 }