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}