LookupSwitchForm.java

  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. import java.util.Arrays;

  21. import org.apache.commons.compress.harmony.unpack200.bytecode.ByteCode;
  22. import org.apache.commons.compress.harmony.unpack200.bytecode.OperandManager;

  23. /**
  24.  * Lookup switch instruction form.
  25.  */
  26. public class LookupSwitchForm extends SwitchForm {

  27.     /**
  28.      * Constructs a new instance with the specified opcode, name, operandType and rewrite.
  29.      *
  30.      * @param opcode  index corresponding to the opcode's value.
  31.      * @param name    String printable name of the opcode.
  32.      */
  33.     public LookupSwitchForm(final int opcode, final String name) {
  34.         super(opcode, name);
  35.     }

  36.     @Override
  37.     public void setByteCodeOperands(final ByteCode byteCode, final OperandManager operandManager, final int codeLength) {
  38.         final int caseCount = operandManager.nextCaseCount();
  39.         final int defaultPc = operandManager.nextLabel();
  40.         final int[] caseValues = new int[caseCount];
  41.         Arrays.setAll(caseValues, i -> operandManager.nextCaseValues());
  42.         final int[] casePcs = new int[caseCount];
  43.         Arrays.setAll(casePcs, i -> operandManager.nextLabel());

  44.         final int[] labelsArray = new int[caseCount + 1];
  45.         labelsArray[0] = defaultPc;
  46.         System.arraycopy(casePcs, 0, labelsArray, 1, caseCount + 1 - 1);
  47.         byteCode.setByteCodeTargets(labelsArray);

  48.         // All this gets dumped into the rewrite bytes of the
  49.         // poor bytecode.

  50.         // Unlike most byte codes, the LookupSwitch is a
  51.         // variable-sized bytecode. Because of this, the
  52.         // rewrite array has to be defined here individually
  53.         // for each bytecode, rather than in the ByteCodeForm
  54.         // class.

  55.         // First, there's the bytecode. Then there are 0-3
  56.         // bytes of padding so that the first (default)
  57.         // label is on a 4-byte offset.
  58.         final int padLength = 3 - codeLength % 4;
  59.         final int rewriteSize = 1 + padLength + 4 // defaultbytes
  60.                 + 4 // npairs
  61.                 + 4 * caseValues.length + 4 * casePcs.length;

  62.         final int[] newRewrite = new int[rewriteSize];
  63.         int rewriteIndex = 0;

  64.         // Fill in what we can now
  65.         // opcode
  66.         newRewrite[rewriteIndex++] = byteCode.getOpcode();

  67.         // padding
  68.         for (int index = 0; index < padLength; index++) {
  69.             newRewrite[rewriteIndex++] = 0;
  70.         }

  71.         // defaultbyte
  72.         // This gets overwritten by fixUpByteCodeTargets
  73.         newRewrite[rewriteIndex++] = -1;
  74.         newRewrite[rewriteIndex++] = -1;
  75.         newRewrite[rewriteIndex++] = -1;
  76.         newRewrite[rewriteIndex++] = -1;

  77.         // npairs
  78.         final int npairsIndex = rewriteIndex;
  79.         setRewrite4Bytes(caseValues.length, npairsIndex, newRewrite);
  80.         rewriteIndex += 4;

  81.         // match-offset pairs
  82.         // The caseValues aren't overwritten, but the
  83.         // casePcs will get overwritten by fixUpByteCodeTargets
  84.         for (final int caseValue : caseValues) {
  85.             // match
  86.             setRewrite4Bytes(caseValue, rewriteIndex, newRewrite);
  87.             rewriteIndex += 4;
  88.             // offset
  89.             newRewrite[rewriteIndex++] = -1;
  90.             newRewrite[rewriteIndex++] = -1;
  91.             newRewrite[rewriteIndex++] = -1;
  92.             newRewrite[rewriteIndex++] = -1;
  93.         }
  94.         byteCode.setRewrite(newRewrite);
  95.     }
  96. }