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}