    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}