001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * https://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.apache.commons.compress.harmony.unpack200.bytecode.forms; 020 021import java.util.Arrays; 022 023import org.apache.commons.compress.harmony.unpack200.bytecode.ByteCode; 024import org.apache.commons.compress.harmony.unpack200.bytecode.OperandManager; 025 026/** 027 * Lookup switch instruction form. 028 */ 029public class LookupSwitchForm extends SwitchForm { 030 031 /** 032 * Constructs a new instance with the specified opcode, name, operandType and rewrite. 033 * 034 * @param opcode index corresponding to the opcode's value. 035 * @param name String printable name of the opcode. 036 */ 037 public LookupSwitchForm(final int opcode, final String name) { 038 super(opcode, name); 039 } 040 041 @Override 042 public void setByteCodeOperands(final ByteCode byteCode, final OperandManager operandManager, final int codeLength) { 043 final int caseCount = operandManager.nextCaseCount(); 044 final int defaultPc = operandManager.nextLabel(); 045 final int[] caseValues = new int[caseCount]; 046 Arrays.setAll(caseValues, i -> operandManager.nextCaseValues()); 047 final int[] casePcs = new int[caseCount]; 048 Arrays.setAll(casePcs, i -> operandManager.nextLabel()); 049 050 final int[] labelsArray = new int[caseCount + 1]; 051 labelsArray[0] = defaultPc; 052 System.arraycopy(casePcs, 0, labelsArray, 1, caseCount + 1 - 1); 053 byteCode.setByteCodeTargets(labelsArray); 054 055 // All this gets dumped into the rewrite bytes of the 056 // poor bytecode. 057 058 // Unlike most byte codes, the LookupSwitch is a 059 // variable-sized bytecode. Because of this, the 060 // rewrite array has to be defined here individually 061 // for each bytecode, rather than in the ByteCodeForm 062 // class. 063 064 // First, there's the bytecode. Then there are 0-3 065 // bytes of padding so that the first (default) 066 // label is on a 4-byte offset. 067 final int padLength = 3 - codeLength % 4; 068 final int rewriteSize = 1 + padLength + 4 // defaultbytes 069 + 4 // npairs 070 + 4 * caseValues.length + 4 * casePcs.length; 071 072 final int[] newRewrite = new int[rewriteSize]; 073 int rewriteIndex = 0; 074 075 // Fill in what we can now 076 // opcode 077 newRewrite[rewriteIndex++] = byteCode.getOpcode(); 078 079 // padding 080 for (int index = 0; index < padLength; index++) { 081 newRewrite[rewriteIndex++] = 0; 082 } 083 084 // defaultbyte 085 // This gets overwritten by fixUpByteCodeTargets 086 newRewrite[rewriteIndex++] = -1; 087 newRewrite[rewriteIndex++] = -1; 088 newRewrite[rewriteIndex++] = -1; 089 newRewrite[rewriteIndex++] = -1; 090 091 // npairs 092 final int npairsIndex = rewriteIndex; 093 setRewrite4Bytes(caseValues.length, npairsIndex, newRewrite); 094 rewriteIndex += 4; 095 096 // match-offset pairs 097 // The caseValues aren't overwritten, but the 098 // casePcs will get overwritten by fixUpByteCodeTargets 099 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}