    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}