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