/*
 * Copyright (C) 2007 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.dx.cf.code;

import com.android.dx.rop.cst.Constant;
import com.android.dx.rop.type.Prototype;
import com.android.dx.rop.type.Type;
import com.android.dx.rop.code.LocalItem;
import java.util.ArrayList;

/**
 * Interface for machines capable of executing bytecode by acting
 * upon a {@link Frame}. A machine conceptually contains four arbitrary-value
 * argument slots, slots for several literal-value arguments, and slots for
 * branch target information.
 */
public interface Machine {
    /**
     * Gets the effective prototype of the method that this instance is
     * being used for. The <i>effective</i> prototype includes an initial
     * <code>this</code> argument for instance methods.
     * 
     * @return non-null; the method prototype
     */
    public Prototype getPrototype();
    
    /**
     * Clears the regular and auxiliary arguments area.
     */
    public void clearArgs();

    /**
     * Pops the given number of values from the stack (of either category),
     * and store them in the arguments area, indicating that there are now
     * that many arguments. Also, clear the auxiliary arguments.
     *
     * @param frame non-null; frame to operate on
     * @param count &gt;= 0; number of values to pop
     */
    public void popArgs(Frame frame, int count);

    /**
     * Pops values from the stack of the types indicated by the given
     * <code>Prototype</code> (popped in reverse of the argument
     * order, so the first prototype argument type is for the deepest
     * element of the stack), and store them in the arguments area,
     * indicating that there are now that many arguments. Also, clear
     * the auxiliary arguments.
     *
     * @param frame non-null; frame to operate on
     * @param prototype non-null; prototype indicating arguments to pop
     */
    public void popArgs(Frame frame, Prototype prototype);

    /**
     * Pops a value from the stack of the indicated type, and store it
     * in the arguments area, indicating that there are now that many
     * arguments. Also, clear the auxiliary arguments.
     *
     * @param frame non-null; frame to operate on
     * @param type non-null; type of the argument
     */
    public void popArgs(Frame frame, Type type);

    /**
     * Pops values from the stack of the indicated types (popped in
     * reverse argument order, so the first indicated type is for the
     * deepest element of the stack), and store them in the arguments
     * area, indicating that there are now that many arguments. Also,
     * clear the auxiliary arguments.
     *
     * @param frame non-null; frame to operate on
     * @param type1 non-null; type of the first argument
     * @param type2 non-null; type of the second argument
     */
    public void popArgs(Frame frame, Type type1, Type type2);

    /**
     * Pops values from the stack of the indicated types (popped in
     * reverse argument order, so the first indicated type is for the
     * deepest element of the stack), and store them in the arguments
     * area, indicating that there are now that many arguments. Also,
     * clear the auxiliary arguments.
     *
     * @param frame non-null; frame to operate on
     * @param type1 non-null; type of the first argument
     * @param type2 non-null; type of the second argument
     * @param type3 non-null; type of the third argument
     */
    public void popArgs(Frame frame, Type type1, Type type2, Type type3);

    /**
     * Loads the local variable with the given index as the sole argument in
     * the arguments area. Also, clear the auxiliary arguments.
     *
     * @param frame non-null; frame to operate on
     * @param idx &gt;= 0; the local variable index
     */
    public void localArg(Frame frame, int idx);

    /**
     * Indicates that the salient type of this operation is as
     * given. This differentiates between, for example, the various
     * arithmetic opcodes, which, by the time they hit a
     * <code>Machine</code> are collapsed to the <code>int</code>
     * variant. (See {@link BytecodeArray#parseInstruction} for
     * details.)
     *
     * @param type non-null; the salient type of the upcoming operation
     */
    public void auxType(Type type);

    /**
     * Indicates that there is an auxiliary (inline, not stack)
     * argument of type <code>int</code>, with the given value.
     *
     * <p><b>Note:</b> Perhaps unintuitively, the stack manipulation
     * ops (e.g., <code>dup</code> and <code>swap</code>) use this to
     * indicate the result stack pattern with a straightforward hex
     * encoding of the push order starting with least-significant
     * nibbles getting pushed first). For example, an all-category-1
     * <code>dup2_x1</code> sets this to <code>0x12312</code>, and the
     * other form of that op sets this to
     * <code>0x121</code>.</p>
     *
     * <p><b>Also Note:</b> For <code>switch*</code> instructions, this is
     * used to indicate the padding value (which is only useful for
     * verification).</p>
     *
     * @param value the argument value
     */
    public void auxIntArg(int value);

    /**
     * Indicates that there is an auxiliary (inline, not stack) object
     * argument, with the value based on the given constant.
     *
     * <p><b>Note:</b> Some opcodes use both <code>int</code> and
     * constant auxiliary arguments.</p>
     *
     * @param cst non-null; the constant containing / referencing
     * the value
     */
    public void auxCstArg(Constant cst);

    /**
     * Indicates that there is an auxiliary (inline, not stack) argument
     * indicating a branch target.
     *
     * @param target the argument value
     */
    public void auxTargetArg(int target);

    /**
     * Indicates that there is an auxiliary (inline, not stack) argument
     * consisting of a <code>switch*</code> table.
     *
     * <p><b>Note:</b> This is generally used in conjunction with
     * {@link #auxIntArg} (which holds the padding).</p>
     *
     * @param cases non-null; the list of key-target pairs, plus the default
     * target
     */
    public void auxSwitchArg(SwitchList cases);

    /**
     * Indicates that there is an auxiliary (inline, not stack) argument
     * consisting of a list of initial values for a newly created array.
     *
     * @param initValues non-null; the list of constant values to initialize
     * the array
     */
    public void auxInitValues(ArrayList<Constant> initValues);

    /**
     * Indicates that the target of this operation is the given local.
     *
     * @param idx &gt;= 0; the local variable index
     * @param type non-null; the type of the local
     * @param local null-ok; the name and signature of the local, if known
     */
    public void localTarget(int idx, Type type, LocalItem local);

    /**
     * "Runs" the indicated opcode in an appropriate way, using the arguments
     * area as appropriate, and modifying the given frame in response.
     *
     * @param frame non-null; frame to operate on
     * @param offset &gt;= 0; byte offset in the method to the opcode being
     * run
     * @param opcode &gt;= 0; the opcode to run
     */
    public void run(Frame frame, int offset, int opcode);
}
