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