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.bcel.generic;
020
021import java.io.DataOutputStream;
022import java.io.IOException;
023
024import org.apache.bcel.Const;
025import org.apache.bcel.ExceptionConst;
026import org.apache.bcel.classfile.ConstantPool;
027import org.apache.bcel.util.ByteSequence;
028
029/**
030 * INVOKEINTERFACE - Invoke interface method
031 *
032 * <PRE>
033 * Stack: ..., objectref, [arg1, [arg2 ...]] -&gt; ...
034 * </PRE>
035 *
036 * @see <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.invokeinterface"> The
037 *      invokeinterface instruction in The Java Virtual Machine Specification</a>
038 */
039public final class INVOKEINTERFACE extends InvokeInstruction {
040
041    private int nargs; // Number of arguments on stack (number of stack slots), called "count" in vmspec2
042
043    /**
044     * Empty constructor needed for Instruction.readInstruction. Not to be used otherwise.
045     */
046    INVOKEINTERFACE() {
047    }
048
049    public INVOKEINTERFACE(final int index, final int nargs) {
050        super(Const.INVOKEINTERFACE, index);
051        super.setLength(5);
052        if (nargs < 1) {
053            throw new ClassGenException("Number of arguments must be > 0 " + nargs);
054        }
055        this.nargs = nargs;
056    }
057
058    /**
059     * Call corresponding visitor method(s). The order is: Call visitor methods of implemented interfaces first, then call
060     * methods according to the class hierarchy in descending order, i.e., the most specific visitXXX() call comes last.
061     *
062     * @param v Visitor object
063     */
064    @Override
065    public void accept(final Visitor v) {
066        v.visitExceptionThrower(this);
067        v.visitTypedInstruction(this);
068        v.visitStackConsumer(this);
069        v.visitStackProducer(this);
070        v.visitLoadClass(this);
071        v.visitCPInstruction(this);
072        v.visitFieldOrMethod(this);
073        v.visitInvokeInstruction(this);
074        v.visitINVOKEINTERFACE(this);
075    }
076
077    @Override
078    public int consumeStack(final ConstantPoolGen cpg) { // nargs is given in byte-code
079        return nargs; // nargs includes this reference
080    }
081
082    /**
083     * Dump instruction as byte code to stream out.
084     *
085     * @param out Output stream
086     */
087    @Override
088    public void dump(final DataOutputStream out) throws IOException {
089        out.writeByte(super.getOpcode());
090        out.writeShort(super.getIndex());
091        out.writeByte(nargs);
092        out.writeByte(0);
093    }
094
095    /**
096     * The <B>count</B> argument according to the Java Language Specification, Second Edition.
097     */
098    public int getCount() {
099        return nargs;
100    }
101
102    @Override
103    public Class<?>[] getExceptions() {
104        return ExceptionConst.createExceptions(ExceptionConst.EXCS.EXCS_INTERFACE_METHOD_RESOLUTION, ExceptionConst.UNSATISFIED_LINK_ERROR,
105            ExceptionConst.ABSTRACT_METHOD_ERROR, ExceptionConst.ILLEGAL_ACCESS_ERROR, ExceptionConst.INCOMPATIBLE_CLASS_CHANGE_ERROR);
106    }
107
108    /**
109     * Reads needed data (i.e., index) from file.
110     */
111    @Override
112    protected void initFromFile(final ByteSequence bytes, final boolean wide) throws IOException {
113        super.initFromFile(bytes, wide);
114        super.setLength(5);
115        nargs = bytes.readUnsignedByte();
116        bytes.readByte(); // Skip 0 byte
117    }
118
119    /**
120     * @return mnemonic for instruction with symbolic references resolved
121     */
122    @Override
123    public String toString(final ConstantPool cp) {
124        return super.toString(cp) + " " + nargs;
125    }
126}