Mercurial > hg > Members > kono > jpf-core
view src/main/gov/nasa/jpf/vm/Instruction.java @ 0:61d41facf527
initial v8 import (history reset)
author | Peter Mehlitz <Peter.C.Mehlitz@nasa.gov> |
---|---|
date | Fri, 23 Jan 2015 10:14:01 -0800 |
parents | |
children | db918c531e6d |
line wrap: on
line source
/* * Copyright (C) 2014, United States Government, as represented by the * Administrator of the National Aeronautics and Space Administration. * All rights reserved. * * The Java Pathfinder core (jpf-core) platform is 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 gov.nasa.jpf.vm; import gov.nasa.jpf.util.ObjectList; import gov.nasa.jpf.util.Source; import gov.nasa.jpf.vm.bytecode.InstructionInterface; /** * common root of all JPF bytecode instruction classes * */ public abstract class Instruction implements Cloneable, InstructionInterface { protected int insnIndex; // code[] index of instruction protected int position; // accumulated bytecode position (prev pos + prev bc-length) protected MethodInfo mi; // the method this insn belongs to // property/mode specific attributes protected Object attr; // this is for changing from InstructionInterface types to Instruction types @Override public Instruction asInstruction(){ return this; } // to allow a classname and methodname context for each instruction public void setContext(String className, String methodName, int lineNumber, int offset) { } /** * is this the first instruction in a method */ @Override public boolean isFirstInstruction() { return (insnIndex == 0); } /** * answer if this is a potential loop closing jump */ @Override public boolean isBackJump() { return false; } /** * is this instruction part of a monitorenter code pattern */ public boolean isMonitorEnterPrologue(){ return false; } /** * is this one of our own, artificial insns? */ @Override public boolean isExtendedInstruction() { return false; } @Override public MethodInfo getMethodInfo() { return mi; } /** * that's used for explicit construction of MethodInfos (synthetic methods) */ public void setMethodInfo(MethodInfo mi) { this.mi = mi; } /** * this returns the instruction at the following code insnIndex within the same * method, which might or might not be the next one to enter (branches, overlay calls etc.). */ @Override public Instruction getNext() { return mi.getInstruction(insnIndex + 1); } @Override public int getInstructionIndex() { return insnIndex; } @Override public int getPosition() { return position; } public void setLocation(int insnIdx, int pos) { insnIndex = insnIdx; position = pos; } /** * return the length in bytes of this instruction. * override if this is not 1 */ @Override public int getLength() { return 1; } @Override public Instruction getPrev() { if (insnIndex > 0) { return mi.getInstruction(insnIndex - 1); } else { return null; } } /** * this is for listeners that process instructionExecuted(), but need to * determine if there was a CG registration, an overlayed direct call * (like clinit) etc. * The easy case is the instruction not having been executed yet, in * which case ti.getNextPC() == null * There are two cases for re-execution: either nextPC was set to the * same insn (which is what CG creators usually use), or somebody just * pushed another stackframe that executes something which will return to the * same insn (that is what automatic <clinit> calls and the like do - we call * it overlays) */ @Override public boolean isCompleted(ThreadInfo ti) { Instruction nextPc = ti.getNextPC(); if (nextPc == null) { return ti.isTerminated(); } else { return (nextPc != this) && (ti.getStackFrameExecuting(this, 1) == null); } // <2do> how do we account for exceptions? } /** * this method can be overridden if instruction classes have to store * information for instructionExecuted() notifications, and this information * should not be stored persistent to avoid memory leaks (e.g. via traces). * Called by ThreadInfo.executeInstruction */ public void cleanupTransients(){ // nothing here } public boolean isSchedulingRelevant(SystemState ss, KernelState ks, ThreadInfo ti) { return false; } /** * this is the real workhorse * returns next instruction to enter in this thread * * <2do> it's unfortunate we roll every side effect into this method, because * it diminishes the value of the 'executeInstruction' notification: all * insns that require some sort of late binding (InvokeVirtual, GetField, ..) * are not yet fully analyzable (e.g. the callee of InvokeVirtuals is not * known yet), putting the burden of duplicating the related code of * enter() in the listener. It would be better if we factor this * 'prepareExecution' out of enter() */ @Override public abstract Instruction execute(ThreadInfo ti); @Override public String toString() { return getMnemonic(); } /** * this can contain additional info that was gathered/cached during execution */ @Override public String toPostExecString(){ return toString(); } @Override public String getMnemonic() { String s = getClass().getSimpleName(); return s.toLowerCase(); } @Override public int getLineNumber() { return mi.getLineNumber(this); } @Override public String getSourceLine() { ClassInfo ci = mi.getClassInfo(); if (ci != null) { int line = mi.getLineNumber(this); String fileName = ci.getSourceFileName(); Source src = Source.getSource(fileName); if (src != null) { String srcLine = src.getLine(line); if (srcLine != null) { return srcLine; } } } return null; } /** * this is for debugging/logging if we always want something back telling * us where this insn came from */ public String getSourceOrLocation(){ ClassInfo ci = mi.getClassInfo(); if (ci != null) { int line = mi.getLineNumber(this); String file = ci.getSourceFileName(); Source src = Source.getSource(file); if (src != null) { String srcLine = src.getLine(line); if (srcLine != null) { return srcLine; } } return "(" + file + ':' + line + ')'; // fallback } else { return "[synthetic] " + mi.getName(); } } /** * this returns a "pathname:line" string */ @Override public String getFileLocation() { ClassInfo ci = mi.getClassInfo(); if (ci != null) { int line = mi.getLineNumber(this); String fname = ci.getSourceFileName(); return (fname + ':' + line); } else { return "[synthetic] " + mi.getName(); } } /** * this returns a "filename:line" string */ @Override public String getFilePos() { String file = null; int line = -1; ClassInfo ci = mi.getClassInfo(); if (ci != null){ line = mi.getLineNumber(this); file = ci.getSourceFileName(); if (file != null){ int i = file.lastIndexOf('/'); // ClassInfo.sourceFileName is using '/' if (i >= 0) { file = file.substring(i + 1); } } } if (file != null) { if (line != -1){ return (file + ':' + line); } else { return file; } } else { return ("pc " + position); } } /** * this returns a "class.method(line)" string */ @Override public String getSourceLocation() { ClassInfo ci = mi.getClassInfo(); if (ci != null) { String s = ci.getName() + '.' + mi.getName() + '(' + getFilePos() + ')'; return s; } else { return null; } } public void init(MethodInfo mi, int offset, int position) { this.mi = mi; this.insnIndex = offset; this.position = position; } /** * this is a misnomer - we actually push the clinit calls here in case * we need some. 'causedClinitCalls' might be more appropriate, but it is * used in a number of external projects */ public boolean requiresClinitExecution(ThreadInfo ti, ClassInfo ci) { return ci.pushRequiredClinits(ti); } /** * this is returning the next Instruction to enter, to be called to obtain * the return value of enter() if this is not a branch insn * * Be aware of that we might have had exceptions caused by our execution * (-> lower frame), or we might have had overlaid calls (-> higher frame), * i.e. we can't simply assume it's the following insn. We have to * acquire this through the top frame of the ThreadInfo. * * note: the System.exit() problem should be gone, now that it is implemented * as ThreadInfo state (TERMINATED), rather than purged stacks */ @Override public Instruction getNext (ThreadInfo ti) { return ti.getPC().getNext(); } //--- the generic attribute API @Override public boolean hasAttr () { return (attr != null); } @Override public boolean hasAttr (Class<?> attrType){ return ObjectList.containsType(attr, attrType); } /** * this returns all of them - use either if you know there will be only * one attribute at a time, or check/process result with ObjectList */ @Override public Object getAttr(){ return attr; } /** * this replaces all of them - use only if you know * - there will be only one attribute at a time * - you obtained the value you set by a previous getXAttr() * - you constructed a multi value list with ObjectList.createList() */ @Override public void setAttr (Object a){ attr = ObjectList.set(attr, a); } @Override public void addAttr (Object a){ attr = ObjectList.add(attr, a); } @Override public void removeAttr (Object a){ attr = ObjectList.remove(attr, a); } @Override public void replaceAttr (Object oldAttr, Object newAttr){ attr = ObjectList.replace(attr, oldAttr, newAttr); } /** * this only returns the first attr of this type, there can be more * if you don't use client private types or the provided type is too general */ @Override public <T> T getAttr (Class<T> attrType) { return ObjectList.getFirst(attr, attrType); } @Override public <T> T getNextAttr (Class<T> attrType, Object prev) { return ObjectList.getNext(attr, attrType, prev); } @Override public ObjectList.Iterator attrIterator(){ return ObjectList.iterator(attr); } @Override public <T> ObjectList.TypedIterator<T> attrIterator(Class<T> attrType){ return ObjectList.typedIterator(attr, attrType); } // -- end attrs -- /** * this is overridden by any Instruction that use a cache for class or * method to provide a type safe cloning */ public Instruction typeSafeClone(MethodInfo mi) { Instruction clone = null; try { clone = (Instruction) super.clone(); // reset the method that this insn belongs to clone.mi = mi; } catch (CloneNotSupportedException e) { e.printStackTrace(); } return clone; } }