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 org.apache.commons.compress.harmony.unpack200.bytecode.ByteCode; 020import org.apache.commons.compress.harmony.unpack200.bytecode.OperandManager; 021 022/** 023 * This class implements the byte code form for the wide instruction. Unlike other instructions, it can take multiple 024 * forms, depending on what is being widened. 025 */ 026public class WideForm extends VariableInstructionForm { 027 028 public WideForm(final int opcode, final String name) { 029 super(opcode, name); 030 } 031 032 /* 033 * (non-Javadoc) 034 * 035 * @see 036 * org.apache.commons.compress.harmony.unpack200.bytecode.forms.ByteCodeForm#setByteCodeOperands(org.apache.commons. 037 * compress.harmony.unpack200.bytecode.ByteCode, 038 * org.apache.commons.compress.harmony.unpack200.bytecode.OperandTable, 039 * org.apache.commons.compress.harmony.unpack200.SegmentConstantPool) 040 */ 041 @Override 042 public void setByteCodeOperands(final ByteCode byteCode, final OperandManager operandManager, 043 final int codeLength) { 044 final int instruction = operandManager.nextWideByteCode(); 045 if (instruction == 132) { 046 setByteCodeOperandsFormat2(instruction, byteCode, operandManager, codeLength); 047 } else { 048 setByteCodeOperandsFormat1(instruction, byteCode, operandManager, codeLength); 049 } 050 } 051 052 /** 053 * This method sets the rewrite array for the bytecode using Format 1 of the JVM spec: an opcode and two index 054 * bytes. This is used for ?load/?store/ret 055 * 056 * @param instruction should be 132 057 * @param byteCode the byte code whose rewrite array should be updated 058 * @param operandManager the source of the operands 059 * @param codeLength ignored 060 */ 061 protected void setByteCodeOperandsFormat1(final int instruction, final ByteCode byteCode, 062 final OperandManager operandManager, final int codeLength) { 063 064 // Even though this code is really similar to the 065 // code for setByteCodeOperandsFormat2, I've left it 066 // distinct here. This is so changing one will 067 // not change the other - if there is a need to change, 068 // there's a good chance that the formats will 069 // differ, so an updater will not have to disentangle 070 // it. 071 final int local = operandManager.nextLocal(); 072 073 // Unlike most byte codes, the wide bytecode is a 074 // variable-sized bytecode. Because of this, the 075 // rewrite array has to be defined here individually 076 // for each bytecode, rather than in the ByteCodeForm 077 // class. 078 079 final int[] newRewrite = new int[4]; 080 int rewriteIndex = 0; 081 082 // Fill in what we can now 083 // wide opcode 084 newRewrite[rewriteIndex++] = byteCode.getOpcode(); 085 086 // "real" instruction that is widened 087 newRewrite[rewriteIndex++] = instruction; 088 089 // Index bytes 090 setRewrite2Bytes(local, rewriteIndex, newRewrite); 091 rewriteIndex += 2; 092 093 byteCode.setRewrite(newRewrite); 094 } 095 096 /** 097 * This method sets the rewrite array for the bytecode using Format 2 of the JVM spec: an opcode, two index bytes, 098 * and two constant bytes. This is used for iinc. 099 * 100 * @param instruction int should be 132 101 * @param byteCode ByteCode whose rewrite array should be updated 102 * @param operandManager OperandManager source of the operands 103 * @param codeLength ignored 104 */ 105 protected void setByteCodeOperandsFormat2(final int instruction, final ByteCode byteCode, 106 final OperandManager operandManager, final int codeLength) { 107 108 final int local = operandManager.nextLocal(); 109 final int constWord = operandManager.nextShort(); 110 111 // Unlike most byte codes, the wide bytecode is a 112 // variable-sized bytecode. Because of this, the 113 // rewrite array has to be defined here individually 114 // for each bytecode, rather than in the ByteCodeForm 115 // class. 116 117 final int[] newRewrite = new int[6]; 118 int rewriteIndex = 0; 119 120 // Fill in what we can now 121 // wide opcode 122 newRewrite[rewriteIndex++] = byteCode.getOpcode(); 123 124 // "real" instruction that is widened 125 newRewrite[rewriteIndex++] = instruction; 126 127 // Index bytes 128 setRewrite2Bytes(local, rewriteIndex, newRewrite); 129 rewriteIndex += 2; 130 131 // constant bytes 132 setRewrite2Bytes(constWord, rewriteIndex, newRewrite); 133 rewriteIndex += 2; // not strictly necessary, but just in case 134 // something comes along later 135 136 byteCode.setRewrite(newRewrite); 137 } 138}