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