All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.ibm.wala.analysis.stackMachine.AbstractIntStackMachine Maven / Gradle / Ivy

/*
 * Copyright (c) 2002 - 2006 IBM Corporation.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 */
package com.ibm.wala.analysis.stackMachine;

import com.ibm.wala.cfg.ShrikeCFG;
import com.ibm.wala.cfg.ShrikeCFG.BasicBlock;
import com.ibm.wala.core.util.CancelRuntimeException;
import com.ibm.wala.core.util.shrike.ShrikeUtil;
import com.ibm.wala.dataflow.graph.AbstractMeetOperator;
import com.ibm.wala.dataflow.graph.BasicFramework;
import com.ibm.wala.dataflow.graph.DataflowSolver;
import com.ibm.wala.dataflow.graph.IKilldallFramework;
import com.ibm.wala.dataflow.graph.ITransferFunctionProvider;
import com.ibm.wala.fixpoint.AbstractStatement;
import com.ibm.wala.fixpoint.AbstractVariable;
import com.ibm.wala.fixpoint.FixedPointConstants;
import com.ibm.wala.fixpoint.UnaryOperator;
import com.ibm.wala.shrike.shrikeBT.ArrayLengthInstruction;
import com.ibm.wala.shrike.shrikeBT.ConstantInstruction;
import com.ibm.wala.shrike.shrikeBT.Constants;
import com.ibm.wala.shrike.shrikeBT.DupInstruction;
import com.ibm.wala.shrike.shrikeBT.IArrayLoadInstruction;
import com.ibm.wala.shrike.shrikeBT.IArrayStoreInstruction;
import com.ibm.wala.shrike.shrikeBT.IBinaryOpInstruction;
import com.ibm.wala.shrike.shrikeBT.IComparisonInstruction;
import com.ibm.wala.shrike.shrikeBT.IConditionalBranchInstruction;
import com.ibm.wala.shrike.shrikeBT.IConversionInstruction;
import com.ibm.wala.shrike.shrikeBT.IGetInstruction;
import com.ibm.wala.shrike.shrikeBT.IInstanceofInstruction;
import com.ibm.wala.shrike.shrikeBT.IInstruction;
import com.ibm.wala.shrike.shrikeBT.IInvokeInstruction;
import com.ibm.wala.shrike.shrikeBT.ILoadInstruction;
import com.ibm.wala.shrike.shrikeBT.IPutInstruction;
import com.ibm.wala.shrike.shrikeBT.IShiftInstruction;
import com.ibm.wala.shrike.shrikeBT.IStoreInstruction;
import com.ibm.wala.shrike.shrikeBT.IUnaryOpInstruction;
import com.ibm.wala.shrike.shrikeBT.MonitorInstruction;
import com.ibm.wala.shrike.shrikeBT.NewInstruction;
import com.ibm.wala.shrike.shrikeBT.PopInstruction;
import com.ibm.wala.shrike.shrikeBT.SwapInstruction;
import com.ibm.wala.shrike.shrikeBT.SwitchInstruction;
import com.ibm.wala.shrike.shrikeBT.ThrowInstruction;
import com.ibm.wala.shrike.shrikeBT.Util;
import com.ibm.wala.types.ClassLoaderReference;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.util.CancelException;
import com.ibm.wala.util.collections.Iterator2Iterable;
import com.ibm.wala.util.graph.INodeWithNumber;
import java.util.Arrays;

/**
 * Skeleton of functionality to propagate information through the Java bytecode stack machine using
 * ShrikeBT.
 *
 * 

This class computes properties the Java operand stack and of the local variables at the * beginning of each basic block. * *

In this implementation, each dataflow variable value is an integer, and the "meeter" object * provides the meets */ public abstract class AbstractIntStackMachine implements FixedPointConstants { private static final boolean DEBUG = false; public static final int TOP = -1; public static final int BOTTOM = -2; public static final int UNANALYZED = -3; public static final int IGNORE = -4; /** The solver */ private DataflowSolver solver; /** The control flow graph to analyze */ private final ShrikeCFG cfg; /** Should uninitialized variables be considered TOP (optimistic) or BOTTOM (pessimistic); */ public static final boolean OPTIMISTIC = true; protected AbstractIntStackMachine(final ShrikeCFG G) { if (G == null) { throw new IllegalArgumentException("G is null"); } this.cfg = G; } protected void init(Meeter meeter, final FlowProvider flow) { final MeetOperator meet = new MeetOperator(meeter); ITransferFunctionProvider xferFunctions = new ITransferFunctionProvider<>() { @Override public boolean hasNodeTransferFunctions() { return flow.needsNodeFlow(); } @Override public boolean hasEdgeTransferFunctions() { return flow.needsEdgeFlow(); } @Override public UnaryOperator getNodeTransferFunction(final BasicBlock node) { return new UnaryOperator<>() { @Override public byte evaluate(MachineState lhs, MachineState rhs) { MachineState exit = lhs; MachineState entry = rhs; MachineState newExit = flow.flow(entry, node); if (newExit.stateEquals(exit)) { return NOT_CHANGED; } else { exit.copyState(newExit); return CHANGED; } } @Override public String toString() { return "NODE-FLOW"; } @Override public int hashCode() { return 9973 * node.hashCode(); } @Override public boolean equals(Object o) { return this == o; } }; } @Override public UnaryOperator getEdgeTransferFunction( final BasicBlock from, final BasicBlock to) { return new UnaryOperator<>() { @Override public byte evaluate(MachineState lhs, MachineState rhs) { MachineState exit = lhs; MachineState entry = rhs; MachineState newExit = flow.flow(entry, from, to); if (newExit.stateEquals(exit)) { return NOT_CHANGED; } else { exit.copyState(newExit); return CHANGED; } } @Override public String toString() { return "EDGE-FLOW"; } @Override public int hashCode() { return 9973 * (from.hashCode() ^ to.hashCode()); } @Override public boolean equals(Object o) { return this == o; } }; } @Override public AbstractMeetOperator getMeetOperator() { return meet; } }; IKilldallFramework problem = new BasicFramework<>(cfg, xferFunctions); solver = new DataflowSolver<>(problem) { private MachineState entry; @Override protected MachineState makeNodeVariable(BasicBlock n, boolean IN) { assert n != null; MachineState result = new MachineState(n); if (IN && n.equals(cfg.entry())) { entry = result; } return result; } @Override protected MachineState makeEdgeVariable(BasicBlock from, BasicBlock to) { assert from != null; assert to != null; MachineState result = new MachineState(from); return result; } @Override protected void initializeWorkList() { super.buildEquations(false, false); /* * Add only the entry variable to the work list. */ for (INodeWithNumber s : Iterator2Iterable.make(getFixedPointSystem().getStatementsThatUse(entry))) { addToWorkList((AbstractStatement) s); } } @Override protected void initializeVariables() { super.initializeVariables(); AbstractIntStackMachine.this.initializeVariables(); } @Override protected MachineState[] makeStmtRHS(int size) { return new MachineState[size]; } }; } public boolean solve() { try { return solver.solve(null); } catch (CancelException e) { throw new CancelRuntimeException(e); } } /** Convenience method ... a little ugly .. perhaps delete later. */ protected void initializeVariables() {} public MachineState getEntryState() { return solver.getIn(cfg.entry()); } /** * @return the state at the entry to a given block */ public MachineState getIn(ShrikeCFG.BasicBlock bb) { return solver.getIn(bb); } private class MeetOperator extends AbstractMeetOperator { private final Meeter meeter; MeetOperator(Meeter meeter) { this.meeter = meeter; } @Override public boolean isUnaryNoOp() { return false; } @Override public byte evaluate(MachineState lhs, MachineState[] rhs) { BasicBlock bb = lhs.getBasicBlock(); if (!bb.isCatchBlock()) { return meet(lhs, rhs, bb, meeter) ? CHANGED : NOT_CHANGED; } else { return meetForCatchBlock(lhs, rhs, bb, meeter) ? CHANGED : NOT_CHANGED; } } @Override public int hashCode() { return 72223 * meeter.hashCode(); } @Override public boolean equals(Object o) { if (o instanceof MeetOperator) { MeetOperator other = (MeetOperator) o; return meeter.equals(other.meeter); } else { return false; } } @Override public String toString() { return "MEETER"; } } /** * A Meeter object provides the dataflow logic needed to meet the abstract machine state for a * dataflow meet. */ protected interface Meeter { /** * Return the integer that represents the meet of a particular stack slot at the entry to a * basic block. * * @param slot The stack slot to meet * @param rhs The values to meet * @param bb The basic block at whose entry this meet occurs * @return The value result of the meet */ int meetStack(int slot, int[] rhs, BasicBlock bb); /** * Return the integer that represents stack slot 0 after a meet at the entry to a catch block. * * @param bb The basic block at whose entry this meet occurs * @return The value of stack slot 0 after the meet */ int meetStackAtCatchBlock(BasicBlock bb); /** * Return the integer that represents the meet of a particular local at the entry to a basic * block. * * @param n The number of the local * @param rhs The values to meet * @param bb The basic block at whose entry this meet occurs * @return The value of local n after the meet. */ int meetLocal(int n, int[] rhs, BasicBlock bb); } /** * Evaluate a meet of machine states. * *

TODO: add some efficiency shortcuts. TODO: clean up and refactor. * * @param bb the basic block at whose entry the meet occurs * @return true if the lhs value changes. false otherwise. */ private static boolean meet(MachineState lhs, MachineState[] rhs, BasicBlock bb, Meeter meeter) { boolean changed = meetStacks(lhs, rhs, bb, meeter); changed |= meetLocals(lhs, rhs, bb, meeter); return changed; } /** * Evaluate a meet of machine states at a catch block. * *

TODO: add some efficiency shortcuts. TODO: clean up and refactor. * * @param bb the basic block at whose entry the meet occurs * @return true if the lhs value changes. false otherwise. */ private static boolean meetForCatchBlock( MachineState lhs, MachineState[] rhs, BasicBlock bb, Meeter meeter) { boolean changed = meetStacksAtCatchBlock(lhs, bb, meeter); changed |= meetLocals(lhs, rhs, bb, meeter); return changed; } /** * Evaluate a meet of the stacks of machine states at the entry of a catch block. * *

TODO: add some efficiency shortcuts. TODO: clean up and refactor. * * @param bb the basic block at whose entry the meet occurs * @return true if the lhs value changes. false otherwise. */ private static boolean meetStacksAtCatchBlock(MachineState lhs, BasicBlock bb, Meeter meeter) { boolean changed = false; // evaluate the meet of the stack of height 1, which holds the exception // object. // allocate lhs.stack if it's // not already allocated. if (lhs.stack == null) { lhs.allocateStack(1); lhs.stackHeight = 1; } int meet = meeter.meetStackAtCatchBlock(bb); if (lhs.stack[0] == TOP) { if (meet != TOP) { changed = true; lhs.stack[0] = meet; } } else if (meet != lhs.stack[0]) { changed = true; lhs.stack[0] = meet; } return changed; } /** * Evaluate a meet of the stacks of machine states at the entry of a basic block. * *

TODO: add some efficiency shortcuts. TODO: clean up and refactor. * * @param bb the basic block at whose entry the meet occurs * @return true if the lhs value changes. false otherwise. */ private static boolean meetStacks( MachineState lhs, MachineState[] rhs, BasicBlock bb, Meeter meeter) { boolean changed = false; // evaluate the element-wise meet over the stacks // first ... how high are the stacks? int height = computeMeetStackHeight(rhs); // if there's any stack height to meet, allocate lhs.stack if it's // not already allocated. if (height > -1 && (lhs.stack == null || lhs.stack.length < height)) { lhs.allocateStack(height); lhs.stackHeight = height; changed = true; } // now do the element-wise meet. for (int i = 0; i < height; i++) { int[] R = new int[rhs.length]; for (int j = 0; j < R.length; j++) { MachineState m = rhs[j]; if (m.stack == null || m.stack.length < i + 1) { R[j] = TOP; } else { R[j] = m.stack[i]; if (R[j] == 0) { R[j] = TOP; } } } int meet = meeter.meetStack(i, R, bb); if (lhs.stack[i] == TOP) { if (meet != TOP) { changed = true; lhs.stack[i] = meet; } } else if (meet != lhs.stack[i]) { changed = true; lhs.stack[i] = meet; } } return changed; } /** * Evaluate a meet of locals of machine states at the entry to a basic block. * *

TODO: add some efficiency shortcuts. TODO: clean up and refactor. * * @param bb the basic block at whose entry the meet occurs * @return true if the lhs value changes. false otherwise. */ private static boolean meetLocals( MachineState lhs, MachineState[] rhs, BasicBlock bb, Meeter meeter) { boolean changed = false; // need we allocate lhs.locals? int nLocals = computeMeetNLocals(rhs); if (nLocals > -1 && (lhs.locals == null || lhs.locals.length < nLocals)) { lhs.allocateLocals(nLocals); } // evaluate the element-wise meet over the locals. for (int i = 0; i < nLocals; i++) { int[] R = new int[rhs.length]; for (int j = 0; j < rhs.length; j++) { R[j] = rhs[j].getLocal(i); } int meet = meeter.meetLocal(i, R, bb); if (lhs.locals[i] == TOP) { if (meet != TOP) { changed = true; lhs.locals[i] = meet; } } else if (meet != lhs.locals[i]) { changed = true; lhs.locals[i] = meet; } } return changed; } /** * @return the number of locals to meet. Return -1 if there is no local meet necessary. * @param operands The operands for this operator. operands[0] is the left-hand side. */ private static int computeMeetNLocals(MachineState[] operands) { MachineState lhs = operands[0]; int nLocals = -1; if (lhs.locals != null) { nLocals = lhs.locals.length; } else { for (int i = 1; i < operands.length; i++) { MachineState rhs = operands[i]; if (rhs.locals != null) { nLocals = rhs.locals.length; break; } } } return nLocals; } /** * @return the height of stacks that are being meeted. Return -1 if there is no stack meet * necessary. * @param operands The operands for this operator. operands[0] is the left-hand side. */ private static int computeMeetStackHeight(MachineState[] operands) { MachineState lhs = operands[0]; int height = -1; if (lhs.stack != null) { height = lhs.stackHeight; } else { for (int i = 1; i < operands.length; i++) { MachineState rhs = operands[i]; if (rhs.stack != null) { height = rhs.stackHeight; break; } } } return height; } /** Representation of the state of the JVM stack machine at some program point. */ public class MachineState extends AbstractVariable { private int[] stack; private int[] locals; // NOTE: stackHeight == -1 is a special code meaning "this variable is TOP" private int stackHeight; private final BasicBlock bb; /** * I'm not using clone because I don't want to necessarily inherit the AbstractVariable state * from the superclass */ public MachineState duplicate() { MachineState result = new MachineState(bb); result.copyState(this); return result; } public MachineState(BasicBlock bb) { setTOP(); this.bb = bb; } public BasicBlock getBasicBlock() { return bb; } void setTOP() { stackHeight = -1; stack = null; } boolean isTOP() { return stackHeight == -1; } public void push(int i) { if (stack == null || stackHeight >= stack.length) allocateStack(stackHeight + 1); stack[stackHeight++] = i; } public int pop() { if (stackHeight <= 0) { assert stackHeight > 0 : "can't pop stack of height " + stackHeight; } stackHeight -= 1; return stack[stackHeight]; } public int peek() { return stack[stackHeight - 1]; } public void swap() { int temp = stack[stackHeight - 1]; stack[stackHeight - 1] = stack[stackHeight - 2]; stack[stackHeight - 2] = temp; } private void allocateStack(int stackHeight) { if (stack == null) { stack = new int[stackHeight + 1]; this.stackHeight = 0; } else { stack = Arrays.copyOf(stack, Math.max(stack.length, stackHeight) * 2 + 1); } } private void allocateLocals(int maxLocals) { int[] result = new int[maxLocals]; int start = 0; if (locals != null) { System.arraycopy(locals, 0, result, 0, locals.length); start = locals.length; } for (int i = start; i < maxLocals; i++) { result[i] = OPTIMISTIC ? TOP : BOTTOM; } locals = result; } public void clearStack() { stackHeight = 0; } /** set the value of local i to symbol j */ public void setLocal(int i, int j) { if (locals == null || locals.length < i + 1) { if (OPTIMISTIC && (j == TOP)) { return; } else { allocateLocals(i + 1); } } locals[i] = j; } /** * @return the number of the symbol corresponding to local i */ public int getLocal(int i) { if (locals == null || locals.length < i + 1) { if (OPTIMISTIC) { return TOP; } else { return BOTTOM; } } else { return locals[i]; } } public void replaceValue(int from, int to) { if (stack != null) for (int i = 0; i < stackHeight; i++) if (stack[i] == from) stack[i] = to; if (locals != null) for (int i = 0; i < locals.length; i++) if (locals[i] == from) locals[i] = to; } public boolean hasValue(int val) { if (stack != null) for (int i = 0; i < stackHeight; i++) if (stack[i] == val) return true; if (locals != null) for (int local : locals) if (local == val) return true; return false; } @Override public String toString() { if (isTOP()) { return "@" + System.identityHashCode(this); } StringBuilder result = new StringBuilder("<"); result.append('S'); if (stackHeight == 0) { result.append("[empty]"); } else { result.append(array2StringBuffer(stack, stackHeight)); } result.append('L'); result.append(array2StringBuffer(locals, locals == null ? 0 : locals.length)); result.append('>'); return result.toString(); } private StringBuilder array2StringBuffer(int[] array, int n) { StringBuilder result = new StringBuilder("["); if (array == null) { result.append(OPTIMISTIC ? "TOP" : "BOTTOM"); } else { for (int i = 0; i < n - 1; i++) { result.append(array[i]).append(','); } result.append(array[n - 1]); } result.append(']'); return result; } @Override public void copyState(MachineState other) { stack = other.stack == null ? null : other.stack.clone(); locals = other.locals == null ? null : other.locals.clone(); stackHeight = other.stackHeight; } boolean stateEquals(MachineState exit) { if (stackHeight != exit.stackHeight) return false; if (locals == null) { if (exit.locals != null) return false; } else { if (exit.locals == null) return false; else if (locals.length != exit.locals.length) return false; } for (int i = 0; i < stackHeight; i++) { if (stack[i] != exit.stack[i]) return false; } if (locals != null) { for (int i = 0; i < locals.length; i++) { if (locals[i] == TOP) { if (exit.locals[i] != TOP) return false; } if (locals[i] != exit.locals[i]) return false; } } return true; } /** * Returns the stackHeight. * * @return int */ public int getStackHeight() { return stackHeight; } /** Use with care. */ public int[] getLocals() { return locals; } } /** Interface which defines a flow function for a basic block */ public interface FlowProvider { boolean needsNodeFlow(); boolean needsEdgeFlow(); /** * Compute the MachineState at the exit of a basic block, given a MachineState at the block's * entry. */ MachineState flow(MachineState entry, BasicBlock basicBlock); /** * Compute the MachineState at the end of an edge, given a MachineState at the edges's entry. */ MachineState flow(MachineState entry, BasicBlock from, BasicBlock to); } /** * This gives some basic facilities for shoving things around on the stack. Client analyses should * subclass this as needed. */ protected abstract static class BasicStackFlowProvider implements FlowProvider, Constants { private final ShrikeCFG cfg; protected MachineState workingState; private BasicStackMachineVisitor visitor; private com.ibm.wala.shrike.shrikeBT.IInstruction.Visitor edgeVisitor; private int currentInstructionIndex = 0; private BasicBlock currentBlock; private BasicBlock currentSuccessorBlock; /** Only subclasses can instantiate */ protected BasicStackFlowProvider(ShrikeCFG cfg) { this.cfg = cfg; } /** Initialize the visitors used to perform the flow functions */ protected void init( BasicStackMachineVisitor v, com.ibm.wala.shrike.shrikeBT.IInstruction.Visitor ev) { this.visitor = v; this.edgeVisitor = ev; } @Override public boolean needsNodeFlow() { return true; } @Override public boolean needsEdgeFlow() { return false; } @Override public MachineState flow(MachineState entry, BasicBlock basicBlock) { workingState = entry.duplicate(); currentBlock = basicBlock; currentSuccessorBlock = null; IInstruction[] instructions = getInstructions(); if (DEBUG) { System.err.println(("Entry to BB" + cfg.getNumber(basicBlock) + ' ' + workingState)); } for (int i = basicBlock.getFirstInstructionIndex(); i <= basicBlock.getLastInstructionIndex(); i++) { currentInstructionIndex = i; instructions[i].visit(visitor); if (DEBUG) { System.err.println(("After " + instructions[i] + ' ' + workingState)); } } return workingState; } @Override public MachineState flow(MachineState entry, BasicBlock from, BasicBlock to) { workingState = entry.duplicate(); currentBlock = from; currentSuccessorBlock = to; IInstruction[] instructions = getInstructions(); if (DEBUG) { System.err.println(("Entry to BB" + cfg.getNumber(from) + ' ' + workingState)); } for (int i = from.getFirstInstructionIndex(); i <= from.getLastInstructionIndex(); i++) { currentInstructionIndex = i; instructions[i].visit(edgeVisitor); if (DEBUG) { System.err.println(("After " + instructions[i] + ' ' + workingState)); } } return workingState; } protected int getCurrentInstructionIndex() { return currentInstructionIndex; } protected int getCurrentProgramCounter() { return cfg.getProgramCounter(currentInstructionIndex); } protected BasicBlock getCurrentBlock() { return currentBlock; } protected BasicBlock getCurrentSuccessor() { return currentSuccessorBlock; } public abstract IInstruction[] getInstructions(); /** Update the machine state to account for an instruction */ protected class BasicStackMachineVisitor extends IInstruction.Visitor { @Override public void visitArrayLength(ArrayLengthInstruction instruction) { workingState.pop(); workingState.push(UNANALYZED); } @Override public void visitArrayLoad(IArrayLoadInstruction instruction) { workingState.pop(); workingState.pop(); workingState.push(UNANALYZED); } @Override public void visitArrayStore(IArrayStoreInstruction instruction) { workingState.pop(); workingState.pop(); workingState.pop(); } @Override public void visitBinaryOp(IBinaryOpInstruction instruction) { workingState.pop(); } @Override public void visitComparison(IComparisonInstruction instruction) { workingState.pop(); workingState.pop(); workingState.push(UNANALYZED); } @Override public void visitConditionalBranch(IConditionalBranchInstruction instruction) { workingState.pop(); workingState.pop(); } @Override public void visitConstant(ConstantInstruction instruction) { workingState.push(UNANALYZED); } @Override public void visitConversion(IConversionInstruction instruction) { workingState.pop(); workingState.push(UNANALYZED); } @Override public void visitDup(DupInstruction instruction) { int size = instruction.getSize(); int delta = instruction.getDelta(); assert size == 1 || size == 2; assert delta == 0 || delta == 1 || delta == 2; int toPop = size + delta; int v1 = workingState.pop(); int v2 = (toPop > 1) ? workingState.pop() : IGNORE; int v3 = (toPop > 2) ? workingState.pop() : IGNORE; int v4 = (toPop > 3) ? workingState.pop() : IGNORE; if (size > 1) { workingState.push(v2); } workingState.push(v1); if (v4 != IGNORE) { workingState.push(v4); } if (v3 != IGNORE) { workingState.push(v3); } if (v2 != IGNORE) { workingState.push(v2); } workingState.push(v1); } @Override public void visitGet(IGetInstruction instruction) { popN(instruction); workingState.push(UNANALYZED); } protected void popN(IInstruction instruction) { for (int i = 0; i < instruction.getPoppedCount(); i++) { workingState.pop(); } } @Override public void visitInstanceof(IInstanceofInstruction instruction) { workingState.pop(); workingState.push(UNANALYZED); } @Override public void visitInvoke(IInvokeInstruction instruction) { popN(instruction); ClassLoaderReference loader = cfg.getMethod().getDeclaringClass().getClassLoader().getReference(); TypeReference returnType = ShrikeUtil.makeTypeReference( loader, Util.getReturnType(instruction.getMethodSignature())); if (!returnType.equals(TypeReference.Void)) { workingState.push(UNANALYZED); } } @Override public void visitMonitor(MonitorInstruction instruction) { workingState.pop(); } @Override public void visitLocalLoad(ILoadInstruction instruction) { int t = workingState.getLocal(instruction.getVarIndex()); workingState.push(t); } @Override public void visitLocalStore(IStoreInstruction instruction) { int index = instruction.getVarIndex(); workingState.setLocal(index, workingState.pop()); } @Override public void visitNew(NewInstruction instruction) { popN(instruction); workingState.push(UNANALYZED); } @Override public void visitPop(PopInstruction instruction) { if (instruction.getPoppedCount() > 0) { workingState.pop(); } } @Override public void visitPut(IPutInstruction instruction) { popN(instruction); } @Override public void visitShift(IShiftInstruction instruction) { workingState.pop(); } @Override public void visitSwap(SwapInstruction instruction) { workingState.swap(); } @Override public void visitSwitch(SwitchInstruction instruction) { workingState.pop(); } @Override public void visitThrow(ThrowInstruction instruction) { int exceptionType = workingState.pop(); workingState.clearStack(); workingState.push(exceptionType); } @Override public void visitUnaryOp(IUnaryOpInstruction instruction) { // treated as a no-op in basic scheme } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy