2 * Copyright (C) 2014, United States Government, as represented by the
3 * Administrator of the National Aeronautics and Space Administration.
6 * The Java Pathfinder core (jpf-core) platform is licensed under the
7 * Apache License, Version 2.0 (the "License"); you may not use this file except
8 * in compliance with the License. You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0.
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
18 package gov.nasa.jpf.vm;
20 import gov.nasa.jpf.util.ObjectList;
21 import gov.nasa.jpf.util.Source;
22 import gov.nasa.jpf.vm.bytecode.InstructionInterface;
27 * common root of all JPF bytecode instruction classes
30 public abstract class Instruction implements Cloneable, InstructionInterface {
32 protected int insnIndex; // code[] index of instruction
33 protected int position; // accumulated bytecode position (prev pos + prev bc-length)
34 protected MethodInfo mi; // the method this insn belongs to
36 // property/mode specific attributes
37 protected Object attr;
39 // this is for changing from InstructionInterface types to Instruction types
41 public Instruction asInstruction(){
45 // to allow a classname and methodname context for each instruction
46 public void setContext(String className, String methodName, int lineNumber,
51 * is this the first instruction in a method
54 public boolean isFirstInstruction() {
55 return (insnIndex == 0);
60 * answer if this is a potential loop closing jump
63 public boolean isBackJump() {
68 * is this instruction part of a monitorenter code pattern
70 public boolean isMonitorEnterPrologue(){
75 * is this one of our own, artificial insns?
78 public boolean isExtendedInstruction() {
84 public MethodInfo getMethodInfo() {
90 * that's used for explicit construction of MethodInfos (synthetic methods)
92 public void setMethodInfo(MethodInfo mi) {
97 * this returns the instruction at the following code insnIndex within the same
98 * method, which might or might not be the next one to enter (branches, overlay calls etc.).
101 public Instruction getNext() {
102 return mi.getInstruction(insnIndex + 1);
106 public int getInstructionIndex() {
111 public int getPosition() {
115 public void setLocation(int insnIdx, int pos) {
121 * return the length in bytes of this instruction.
122 * override if this is not 1
125 public int getLength() {
130 public Instruction getPrev() {
132 return mi.getInstruction(insnIndex - 1);
139 * this is for listeners that process instructionExecuted(), but need to
140 * determine if there was a CG registration, an overlayed direct call
142 * The easy case is the instruction not having been executed yet, in
143 * which case ti.getNextPC() == null
144 * There are two cases for re-execution: either nextPC was set to the
145 * same insn (which is what CG creators usually use), or somebody just
146 * pushed another stackframe that executes something which will return to the
147 * same insn (that is what automatic <clinit> calls and the like do - we call
151 public boolean isCompleted(ThreadInfo ti) {
152 Instruction nextPc = ti.getNextPC();
154 if (nextPc == null) {
155 return ti.isTerminated();
159 return (nextPc != this) && (ti.getStackFrameExecuting(this, 1) == null);
162 // <2do> how do we account for exceptions?
166 * this method can be overridden if instruction classes have to store
167 * information for instructionExecuted() notifications, and this information
168 * should not be stored persistent to avoid memory leaks (e.g. via traces).
169 * Called by ThreadInfo.executeInstruction
171 public void cleanupTransients(){
175 public boolean isSchedulingRelevant(SystemState ss, KernelState ks, ThreadInfo ti) {
180 * this is the real workhorse
181 * returns next instruction to enter in this thread
183 * <2do> it's unfortunate we roll every side effect into this method, because
184 * it diminishes the value of the 'executeInstruction' notification: all
185 * insns that require some sort of late binding (InvokeVirtual, GetField, ..)
186 * are not yet fully analyzable (e.g. the callee of InvokeVirtuals is not
187 * known yet), putting the burden of duplicating the related code of
188 * enter() in the listener. It would be better if we factor this
189 * 'prepareExecution' out of enter()
192 public abstract Instruction execute(ThreadInfo ti);
195 public String toString() {
196 return getMnemonic();
200 * this can contain additional info that was gathered/cached during execution
203 public String toPostExecString(){
208 public String getMnemonic() {
209 String s = getClass().getSimpleName();
210 return s.toLowerCase();
214 public int getLineNumber() {
215 return mi.getLineNumber(this);
219 public String getSourceLine() {
220 ClassInfo ci = mi.getClassInfo();
222 int line = mi.getLineNumber(this);
223 String fileName = ci.getSourceFileName();
225 Source src = Source.getSource(fileName);
227 String srcLine = src.getLine(line);
228 if (srcLine != null) {
238 * this is for debugging/logging if we always want something back telling
239 * us where this insn came from
241 public String getSourceOrLocation(){
242 ClassInfo ci = mi.getClassInfo();
244 int line = mi.getLineNumber(this);
245 String file = ci.getSourceFileName();
247 Source src = Source.getSource(file);
249 String srcLine = src.getLine(line);
250 if (srcLine != null) {
255 return "(" + file + ':' + line + ')'; // fallback
258 return "[synthetic] " + mi.getName();
264 * this returns a "pathname:line" string
267 public String getFileLocation() {
268 ClassInfo ci = mi.getClassInfo();
270 int line = mi.getLineNumber(this);
271 String fname = ci.getSourceFileName();
272 return (fname + ':' + line);
274 return "[synthetic] " + mi.getName();
279 * this returns a "filename:line" string
282 public String getFilePos() {
285 ClassInfo ci = mi.getClassInfo();
288 line = mi.getLineNumber(this);
289 file = ci.getSourceFileName();
291 int i = file.lastIndexOf('/'); // ClassInfo.sourceFileName is using '/'
293 file = file.substring(i + 1);
300 return (file + ':' + line);
305 return ("pc " + position);
310 * this returns a "class.method(line)" string
313 public String getSourceLocation() {
314 ClassInfo ci = mi.getClassInfo();
317 String s = ci.getName() + '.' + mi.getName() +
318 '(' + getFilePos() + ')';
326 public void init(MethodInfo mi, int offset, int position) {
328 this.insnIndex = offset;
329 this.position = position;
333 * this is a misnomer - we actually push the clinit calls here in case
334 * we need some. 'causedClinitCalls' might be more appropriate, but it is
335 * used in a number of external projects
337 public boolean requiresClinitExecution(ThreadInfo ti, ClassInfo ci) {
338 return ci.initializeClass(ti);
342 * this is returning the next Instruction to enter, to be called to obtain
343 * the return value of enter() if this is not a branch insn
345 * Be aware of that we might have had exceptions caused by our execution
346 * (-> lower frame), or we might have had overlaid calls (-> higher frame),
347 * i.e. we can't simply assume it's the following insn. We have to
348 * acquire this through the top frame of the ThreadInfo.
350 * note: the System.exit() problem should be gone, now that it is implemented
351 * as ThreadInfo state (TERMINATED), rather than purged stacks
354 public Instruction getNext (ThreadInfo ti) {
355 return ti.getPC().getNext();
359 //--- the generic attribute API
362 public boolean hasAttr () {
363 return (attr != null);
367 public boolean hasAttr (Class<?> attrType){
368 return ObjectList.containsType(attr, attrType);
372 * this returns all of them - use either if you know there will be only
373 * one attribute at a time, or check/process result with ObjectList
376 public Object getAttr(){
381 * this replaces all of them - use only if you know
382 * - there will be only one attribute at a time
383 * - you obtained the value you set by a previous getXAttr()
384 * - you constructed a multi value list with ObjectList.createList()
387 public void setAttr (Object a){
388 attr = ObjectList.set(attr, a);
392 public void addAttr (Object a){
393 attr = ObjectList.add(attr, a);
397 public void removeAttr (Object a){
398 attr = ObjectList.remove(attr, a);
402 public void replaceAttr (Object oldAttr, Object newAttr){
403 attr = ObjectList.replace(attr, oldAttr, newAttr);
407 * this only returns the first attr of this type, there can be more
408 * if you don't use client private types or the provided type is too general
411 public <T> T getAttr (Class<T> attrType) {
412 return ObjectList.getFirst(attr, attrType);
416 public <T> T getNextAttr (Class<T> attrType, Object prev) {
417 return ObjectList.getNext(attr, attrType, prev);
421 public ObjectList.Iterator attrIterator(){
422 return ObjectList.iterator(attr);
426 public <T> ObjectList.TypedIterator<T> attrIterator(Class<T> attrType){
427 return ObjectList.typedIterator(attr, attrType);
433 * this is overridden by any Instruction that use a cache for class or
434 * method to provide a type safe cloning
436 public Instruction typeSafeClone(MethodInfo mi) {
437 Instruction clone = null;
440 clone = (Instruction) super.clone();
442 // reset the method that this insn belongs to
444 } catch (CloneNotSupportedException e) {