    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}