// // Copyright (C) 2006 United States Government as represented by the // Administrator of the National Aeronautics and Space Administration // (NASA). All Rights Reserved. // // This software is distributed under the NASA Open Source Agreement // (NOSA), version 1.3. The NOSA has been approved by the Open Source // Initiative. See the file NOSA-1.3-JPF at the top of the distribution // directory tree for the complete NOSA document. // // THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY // KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT // LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO // SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR // A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT // THE SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT // DOCUMENTATION, IF PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE. // package gov.nasa.jpf.vm; import java.util.Date; import java.util.HashMap; import java.util.Locale; import java.util.function.BiFunction; import cmu.conditional.Conditional; import cmu.conditional.One; import de.fosd.typechef.featureexpr.FeatureExpr; import de.fosd.typechef.featureexpr.FeatureExprFactory; import gov.nasa.jpf.Config; import gov.nasa.jpf.JPF; import gov.nasa.jpf.JPFException; import gov.nasa.jpf.JPFListener; /** * MJIEnv is the call environment for "native" methods, i.e. code that * is executed by the VM, not by JPF. * * Since library abstractions are supposed to be "user code", we provide * this class as a (little bit of) insulation towards the inner JPF workings. * * There are two APIs exported by this class. The public methods (like * getStringObject) don't expose JPF internals, and can be used from non * gov.nasa.jpf.vm NativePeer classes). The rest is package-default * and can be used to fiddle around as much as you like to (if you are in * the ..jvm package) * * Note that MJIEnv objects are now per-ThreadInfo (i.e. the variable * call envionment only includes MethodInfo and ClassInfo), which means * MJIEnv can be used in non-native methods (but only carefully, if you * don't need mi or ciMth). * * Note also this only works because we are not getting recursive in * native method calls. In fact, the whole DirectCallStackFrame / repeatTopInstruction * mechanism is there to turn logial recursion (JPF calling native, calling * JPF, calling native,..) into iteration. Otherwise we couldn't backtrack */ public class MJIEnv { public static final int NULL = 0; VM vm; ClassInfo ciMth; // the ClassInfo of the method this is called from MethodInfo mi; ThreadInfo ti; Heap heap; // those are various attributes set by the execution. note that // NativePeer.invoke never gets recursive in a roundtrip (at least if // used correctly, so we don't have to be afraid to overwrite any of these boolean repeat; Object returnAttr; // exception to be thrown upon return from native method // NOTE: this is only transient - don't expect this to be preserved over // transition boundaries int exceptionRef; protected MJIEnv (ThreadInfo ti) { this.ti = ti; // set those here so that we don't have an inconsistent state between // creation of an MJI object and the first native method call in // this thread (where any access to the heap or sa would bomb) vm = ti.getVM(); heap = vm.getHeap(); exceptionRef = NULL; } public MJIEnv() { // TODO Auto-generated constructor stub } public VM getVM () { return vm; } public JPF getJPF () { return vm.getJPF(); } public boolean isBigEndianPlatform(){ return vm.isBigEndianPlatform(); } public void addListener (JPFListener l){ vm.getJPF().addListener(l); } public void removeListener (JPFListener l){ vm.getJPF().removeListener(l); } public Config getConfig() { return vm.getConfig(); } public void gc() { heap.gc(); } public void ignoreTransition () { getSystemState().setIgnored(true); } public boolean isArray (int objref) { return heap.get(objref).isArray(); } public int getArrayLength (FeatureExpr ctx, int objref) { if (isArray(objref)) { return heap.get(objref).arrayLength().getValue(); } else { throwException(ctx, "java.lang.IllegalArgumentException"); return 0; } } public String getArrayType (int objref) { return heap.get(objref).getArrayType(); } public int getArrayTypeSize (int objref) { return Types.getTypeSize(getArrayType(objref)); } //=== various attribute accessors ============================================ // we only support some attribute APIs here, since MJIEnv adds little value // other than hiding the ElementInfo access. If the client already has // an ElementInfo reference, it should use that one to retrieve/enumerate/set // attributes since this avoids repeated Heap.get() calls //--- object attributes public boolean hasObjectAttr (int objref){ if (objref != NULL){ ElementInfo ei = heap.get(objref); return ei.hasObjectAttr(); } return false; } public boolean hasObjectAttr (int objref, Class<?> type){ if (objref != NULL){ ElementInfo ei = heap.get(objref); return ei.hasObjectAttr(type); } return false; } /** * 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 */ public Object getObjectAttr (int objref){ if (objref != NULL){ ElementInfo ei = heap.get(objref); return ei.getObjectAttr(); } return null; } /** * 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() */ public void setObjectAttr (int objref, Object a){ if (objref != NULL){ ElementInfo ei = heap.get(objref); ei.setObjectAttr(a); } } public void addObjectAttr (int objref, Object a){ if (objref != NULL){ ElementInfo ei = heap.getModifiable(objref); ei.addObjectAttr(a); } } /** * 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 */ public <T> T getObjectAttr (int objref, Class<T> attrType){ ElementInfo ei = heap.get(objref); return ei.getObjectAttr(attrType); } //--- field attributes public boolean hasFieldAttr (int objref){ if (objref != NULL){ ElementInfo ei = heap.get(objref); return ei.hasFieldAttr(); } return false; } public boolean hasFieldAttr (int objref, Class<?> type){ if (objref != NULL){ ElementInfo ei = heap.get(objref); return ei.hasFieldAttr(type); } return false; } /** * 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 */ public Object getFieldAttr (int objref, String fname){ ElementInfo ei = heap.get(objref); FieldInfo fi = ei.getFieldInfo(fname); if (fi != null){ return ei.getFieldAttr(fi); } else { throw new JPFException("no such field: " + fname); } } /** * 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() */ public void setFieldAttr (int objref, String fname, Object a){ if (objref != NULL){ ElementInfo ei = heap.get(objref); FieldInfo fi = ei.getFieldInfo(fname); ei.setFieldAttr(fi, a); } } public void addFieldAttr (int objref, String fname, Object a){ if (objref != NULL){ ElementInfo ei = heap.getModifiable(objref); FieldInfo fi = ei.getFieldInfo(fname); ei.addFieldAttr(fi, a); } } /** * 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 */ public <T> T getFieldAttr (int objref, String fname, Class<T> attrType){ ElementInfo ei = heap.get(objref); FieldInfo fi = ei.getFieldInfo(fname); if (fi != null){ return ei.getFieldAttr(fi, attrType); } else { throw new JPFException("no such field: " + fname); } } //--- element attrs public boolean hasElementdAttr (int objref){ if (objref != NULL){ ElementInfo ei = heap.get(objref); return ei.hasElementAttr(); } return false; } public boolean hasElementAttr (int objref, Class<?> type){ if (objref != NULL){ ElementInfo ei = heap.get(objref); return ei.hasElementAttr(type); } return false; } /** * 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 */ public Object getElementAttr (int objref, int idx){ ElementInfo ei = heap.get(objref); return ei.getElementAttr(idx); } /** * 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() */ public void setElementAttr (int objref, int idx, Object a){ ElementInfo ei = heap.get(objref); ei.setElementAttr(idx, a); } public void addElementAttr (int objref, int idx, Object a){ ElementInfo ei = heap.getModifiable(objref); ei.addElementAttr(idx, a); } /** * 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 */ public <T> T getElementAttr (int objref, int idx, Class<T> attrType){ if (objref != NULL){ ElementInfo ei = heap.get(objref); return ei.getElementAttr(idx, attrType); } return null; } // == end attrs == // the instance field setters public void setBooleanField (FeatureExpr ctx, int objref, String fname, Conditional<Boolean> val) { heap.getModifiable(objref).setBooleanField(ctx, fname, val); } public Conditional<Boolean> getBooleanField (int objref, String fname) { return heap.get(objref).getBooleanField(fname); } public Conditional<Boolean> getBooleanArrayElement (int objref, int index) { return heap.get(objref).getBooleanElement(index); } public void setBooleanArrayElement (FeatureExpr ctx, int objref, int index, Conditional<Boolean> value) { heap.getModifiable(objref).setBooleanElement(ctx, index, value); } public void setByteField (FeatureExpr ctx, int objref, String fname, Conditional<Byte> val) { heap.getModifiable(objref).setByteField(ctx, fname, val); } public Conditional<Byte> getByteField (int objref, String fname) { return heap.get(objref).getByteField(fname); } public void setCharField (FeatureExpr ctx, int objref, String fname, Conditional<Character> val) { heap.getModifiable(objref).setCharField(ctx, fname, val); } public Conditional<Character> getCharField (int objref, String fname) { return heap.get(objref).getCharField(fname); } public void setDoubleField (FeatureExpr ctx, int objref, String fname, Conditional<Double> val) { heap.getModifiable(objref).setDoubleField(ctx, fname, val); } public Conditional<Double> getDoubleField (int objref, String fname) { return heap.get(objref).getDoubleField(fname); } public void setFloatField (FeatureExpr ctx, int objref, String fname, Conditional<Float> val) { heap.getModifiable(objref).setFloatField(ctx, fname, val); } public Conditional<Float> getFloatField (int objref, String fname) { return heap.get(objref).getFloatField(fname); } public void setByteArrayElement (FeatureExpr ctx, int objref, int index, Conditional<Byte> value) { heap.getModifiable(objref).setByteElement(ctx, index, value); } public Conditional<Byte> getByteArrayElement (int objref, int index) { return heap.get(objref).getByteElement(index); } public void setCharArrayElement (FeatureExpr ctx, int objref, int index, Conditional<Character> value) { heap.getModifiable(objref).setCharElement(ctx, index, value); } public void setIntArrayElement (FeatureExpr ctx, int objref, int index, Conditional<Integer> value) { heap.getModifiable(objref).setIntElement(ctx, index, value); } public void setShortArrayElement (FeatureExpr ctx, int objref, int index, Conditional<Short> value) { heap.getModifiable(objref).setShortElement(ctx, index, value); } public void setFloatArrayElement (FeatureExpr ctx, int objref, int index, Conditional<Float> value) { heap.getModifiable(objref).setFloatElement(ctx, index, value); } public Conditional<Float> getFloatArrayElement (int objref, int index) { return heap.get(objref).getFloatElement(index); } public Conditional<Double> getDoubleArrayElement (int objref, int index) { return heap.get(objref).getDoubleElement(index); } public void setDoubleArrayElement (FeatureExpr ctx, int objref, int index, Conditional<Double> value) { heap.getModifiable(objref).setDoubleElement(ctx, index, value); } public Conditional<Short> getShortArrayElement (int objref, int index) { return heap.get(objref).getShortElement(index); } public Conditional<Integer> getIntArrayElement (int objref, int index) { return heap.get(objref).getIntElement(index); } public Conditional<Character> getCharArrayElement (int objref, int index) { return heap.get(objref).getCharElement(index); } public void setIntField (FeatureExpr ctx, int objref, String fname, Conditional<Integer> val) { ElementInfo ei = heap.getModifiable(objref); ei.setIntField(ctx, fname, val); } // these two are the workhorses public void setDeclaredIntField (FeatureExpr ctx, int objref, String refType, String fname, Conditional<Integer> val) { ElementInfo ei = heap.getModifiable(objref); ei.setDeclaredIntField(ctx, fname, refType, val); } public Conditional<Integer> getIntField (int objref, String fname) { ElementInfo ei = heap.get(objref); return ei.getIntField(fname); } public int getDeclaredIntField (int objref, String refType, String fname) { ElementInfo ei = heap.get(objref); return ei.getDeclaredIntField(fname, refType);// TODO jens } // these two are the workhorses public void setDeclaredReferenceField (int objref, String refType, String fname, int val) {// TODO jens ElementInfo ei = heap.getModifiable(objref); ei.setDeclaredReferenceField(fname, refType, val); } public void setReferenceField (FeatureExpr ctx, int objref, String fname, int ref) {// TODO jens ElementInfo ei = heap.getModifiable(objref); ei.setReferenceField(ctx, fname, new One<>(ref)); } public Conditional<Integer> getReferenceField (FeatureExpr ctx, int objref, String fname) { ElementInfo ei = heap.get(objref); return ei.getReferenceField(fname).simplify(ctx);// TODO jens } // we need this in case of a masked field public int getReferenceField (FeatureExpr ctx, int objref, FieldInfo fi) { ElementInfo ei = heap.get(objref); return ei.getReferenceField(fi).simplify(ctx).getValue();// TODO jens } public String getStringField (FeatureExpr ctx, int objref, String fname){// TODO jens int ref = getReferenceField(ctx, objref, fname).getValue(); return getStringObject(ctx, ref); } // the box object accessors (should probably test for the appropriate class) public Conditional<Boolean> getBooleanValue (int objref) { return getBooleanField(objref, "value"); } public Conditional<Byte> getByteValue (int objref) { return getByteField(objref, "value"); } public Conditional<Character> getCharValue (int objref) { return getCharField(objref, "value"); } public Conditional<Short> getShortValue (int objref) { return getShortField(objref, "value"); } public Conditional<Integer> getIntValue (int objref) { return getIntField(objref, "value"); } public Conditional<Long> getLongValue (int objref) { return getLongField(objref, "value"); } public Conditional<Float> getFloatValue (int objref) { return getFloatField(objref, "value"); } public Conditional<Double> getDoubleValue (int objref) { return getDoubleField(objref, "value"); } public void setLongArrayElement (FeatureExpr ctx, int objref, int index, Conditional<Long> value) { heap.getModifiable(objref).setLongElement(ctx, index, value); } public Conditional<Long> getLongArrayElement (int objref, int index) { return heap.get(objref).getLongElement(index); } public void setLongField (FeatureExpr ctx, int objref, String fname, Conditional<Long> val) { ElementInfo ei = heap.getModifiable(objref); ei.setLongField(ctx, fname, val); } // public void setLongField (int objref, String refType, String fname, long val) { // ElementInfo ei = heap.get(objref); // ei.setLongField(fname, refType, val); // } public Conditional<Long> getLongField (int objref, String fname) { ElementInfo ei = heap.get(objref); return ei.getLongField(fname); } // public long getLongField (int objref, String refType, String fname) { // ElementInfo ei = heap.get(objref); // return ei.getLongField(fname, refType); // } public void setReferenceArrayElement (FeatureExpr ctx, int objref, int index, Conditional<Integer> eRef) { heap.getModifiable(objref).setReferenceElement(ctx, index, eRef); } public Conditional<Integer> getReferenceArrayElement (int objref, int index) { return heap.get(objref).getReferenceElement(index); } public void setShortField (FeatureExpr ctx, int objref, String fname, Conditional<Short> val) { ElementInfo ei = heap.getModifiable(objref); ei.setShortField(ctx, fname, val); } public Conditional<Short> getShortField (int objref, String fname) { ElementInfo ei = heap.get(objref); return ei.getShortField(fname); } public String getTypeName (int objref) { return heap.get(objref).getType(); } public boolean isInstanceOf (int objref, String clsName) { ClassInfo ci = getClassInfo(objref); return ci.isInstanceOf(clsName); } //--- the static field accessors // NOTE - it is the callers responsibility to ensure the class is // properly initialized, since calling <clinit> requires a roundtrip // (i.e. cannot be done synchronously from one of the following methods) // <2do> this uses the current system CL, we should probably use an explicit CL argument public void setStaticBooleanField (FeatureExpr ctx, String clsName, String fname, Conditional<Boolean> value) { ClassInfo ci = ClassLoaderInfo.getCurrentResolvedClassInfo(clsName); ci.getStaticElementInfo().setBooleanField(ctx, fname, value); } public void setStaticBooleanField (FeatureExpr ctx, int clsObjRef, String fname, Conditional<Boolean> val) { ElementInfo cei = getStaticElementInfo(clsObjRef); cei.setBooleanField(ctx, fname, val); } public Conditional<Boolean> getStaticBooleanField (String clsName, String fname) { ClassInfo ci = ClassLoaderInfo.getCurrentResolvedClassInfo(clsName); return ci.getStaticElementInfo().getBooleanField(fname); } public void setStaticByteField (FeatureExpr ctx, String clsName, String fname, Conditional<Byte> value) { ClassInfo ci = ClassLoaderInfo.getCurrentResolvedClassInfo(clsName); ci.getStaticElementInfo().setByteField(ctx, fname, value); } public Conditional<Byte> getStaticByteField (String clsName, String fname) { ClassInfo ci = ClassLoaderInfo.getCurrentResolvedClassInfo(clsName); return ci.getStaticElementInfo().getByteField(fname); } public void setStaticCharField (FeatureExpr ctx, String clsName, String fname, Conditional<Character> value) { ClassInfo ci = ClassLoaderInfo.getCurrentResolvedClassInfo(clsName); ci.getStaticElementInfo().setCharField(ctx, fname, value); } public Conditional<Character> getStaticCharField (String clsName, String fname) { ClassInfo ci = ClassLoaderInfo.getCurrentResolvedClassInfo(clsName); return ci.getStaticElementInfo().getCharField(fname); } public void setStaticDoubleField (FeatureExpr ctx, String clsName, String fname, Conditional<Double> val) { ClassInfo ci = ClassLoaderInfo.getCurrentResolvedClassInfo(clsName); ci.getStaticElementInfo().setDoubleField(ctx, fname, val); } public Conditional<Double> getStaticDoubleField (String clsName, String fname) { ClassInfo ci = ClassLoaderInfo.getCurrentResolvedClassInfo(clsName); return ci.getStaticElementInfo().getDoubleField(fname); } public Conditional<Double> getStaticDoubleField (int clsObjRef, String fname) { ElementInfo cei = getStaticElementInfo(clsObjRef); return cei.getDoubleField(fname); } public Conditional<Double> getStaticDoubleField (ClassInfo ci, String fname) { ElementInfo ei = ci.getStaticElementInfo(); return ei.getDoubleField(fname); } public void setStaticFloatField (FeatureExpr ctx, String clsName, String fname, Conditional<Float> val) { ClassInfo ci = ClassLoaderInfo.getCurrentResolvedClassInfo(clsName); ci.getStaticElementInfo().setFloatField(ctx, fname, val); } public Conditional<Float> getStaticFloatField (String clsName, String fname) { ClassInfo ci = ClassLoaderInfo.getCurrentResolvedClassInfo(clsName); return ci.getStaticElementInfo().getFloatField(fname); } public void setStaticIntField (FeatureExpr ctx, String clsName, String fname, Conditional<Integer> val) { ClassInfo ci = ClassLoaderInfo.getCurrentResolvedClassInfo(clsName); ci.getStaticElementInfo().setIntField(ctx, fname, val); } public void setStaticIntField (FeatureExpr ctx, int clsObjRef, String fname, Conditional<Integer> val) { ElementInfo cei = getStaticElementInfo(clsObjRef); cei.setIntField(ctx, fname, val); } public int getStaticIntField (String clsName, String fname) { ClassInfo ci = ClassLoaderInfo.getCurrentResolvedClassInfo(clsName); return ci.getStaticElementInfo().getIntField(fname).simplify(null).getValue();// TODO jens } public int getStaticIntField (int clsObjRef, String fname) { ElementInfo cei = getStaticElementInfo(clsObjRef); return cei.getIntField(fname).simplify(null).getValue();// TODO jens } public int getStaticIntField (ClassInfo ci, String fname) { ElementInfo ei = ci.getStaticElementInfo(); return ei.getIntField(fname).simplify(null).getValue();// TODO jens } public void setStaticLongField (FeatureExpr ctx, String clsName, String fname, Conditional<Long> value) { ClassInfo ci = ClassLoaderInfo.getCurrentResolvedClassInfo(clsName); ci.getStaticElementInfo().setLongField(ctx, fname, value); } public void setStaticLongField (FeatureExpr ctx, int clsObjRef, String fname, Conditional<Long> val) { ElementInfo cei = getModifiableStaticElementInfo(clsObjRef); cei.setLongField(ctx, fname, val); } public long getStaticLongField (int clsRef, String fname) { ClassInfo ci = getReferredClassInfo(FeatureExprFactory.True(), clsRef);// TODO jens return getStaticLongField(ci,fname); } public long getStaticLongField (String clsName, String fname) { ClassInfo ci = ClassLoaderInfo.getCurrentResolvedClassInfo(clsName); return getStaticLongField(ci, fname); } public long getStaticLongField (ClassInfo ci, String fname){ ElementInfo ei = ci.getStaticElementInfo(); return ei.getLongField(fname).getValue();// TODO jens } public void setStaticReferenceField (FeatureExpr ctx, String clsName, String fname, int objref) {// TODO jens ClassInfo ci = ClassLoaderInfo.getCurrentResolvedClassInfo(clsName); // <2do> - we should REALLY check for type compatibility here ci.getModifiableStaticElementInfo().setReferenceField(ctx, fname, new One<>(objref)); } public void setStaticReferenceField (int clsObjRef, String fname, int objref) { ElementInfo cei = getModifiableStaticElementInfo(clsObjRef); // <2do> - we should REALLY check for type compatibility here cei.setReferenceField(null, fname, new One<>(objref));// TODO jens } public int getStaticReferenceField (String clsName, String fname) { ClassInfo ci = ClassLoaderInfo.getCurrentResolvedClassInfo(clsName); return ci.getStaticElementInfo().getReferenceField(fname).getValue();// TODO jens } public int getStaticReferenceField (int clsObjRef, String fname) { ElementInfo cei = getStaticElementInfo(clsObjRef); return cei.getReferenceField(fname).getValue();// TODO jens } public int getStaticReferenceField (ClassInfo ci, String fname){ return ci.getStaticElementInfo().getReferenceField(fname).getValue();// TODO jens } public Conditional<Short> getStaticShortField (String clsName, String fname) { ClassInfo ci = ClassLoaderInfo.getCurrentResolvedClassInfo(clsName); return ci.getStaticElementInfo().getShortField(fname); } public Conditional<char[]> getStringChars (int objRef){ if (objRef != MJIEnv.NULL) { ElementInfo ei = getElementInfo(objRef); return ei.getStringChars(); } else { return null; } } /** * {@link #getStringObjectNew(FeatureExpr, int)} */ @Deprecated public String getStringObject (FeatureExpr ctx, int objRef) { if (objRef != MJIEnv.NULL) { ElementInfo ei = getElementInfo(objRef); Conditional<String> str = ei.asString(); return str.simplify(ctx).getValue(); } else { return null; } } /** * turn JPF String object into a VM String object * (this is a method available for non gov..jvm NativePeer classes) */ public Conditional<String> getStringObject (FeatureExpr ctx, Conditional<Integer> objRef) { return objRef.mapf(ctx, new BiFunction<FeatureExpr, Integer, Conditional<String>>() { @Override public Conditional<String> apply(FeatureExpr ctx, Integer objRef) { return getStringObjectNew(ctx, objRef); } }).simplify(); } /** * turn JPF String object into a VM String object * (this is a method available for non gov..jvm NativePeer classes) */ public Conditional<String> getStringObjectNew (FeatureExpr ctx, int objRef) { if (objRef != MJIEnv.NULL) { ElementInfo ei = getElementInfo(objRef); Conditional<String> str = ei.asString(); return str.simplify(ctx); } else { return null; } } @SuppressWarnings("unchecked") public Conditional<String> getConditionalStringObject (int objRef) { if (objRef != MJIEnv.NULL) { ElementInfo ei = getElementInfo(objRef); return ei.asString(); } else { return (Conditional<String>) One.NULL; } } public String[] getStringArrayObject (FeatureExpr ctx, int aRef){ String[] sa = null; if (aRef == NULL) { return sa; } ClassInfo aci = getClassInfo(aRef); if (aci.isArray()){ ClassInfo eci = aci.getComponentClassInfo(); if (eci.getName().equals("java.lang.String")){ int len = getArrayLength(ctx, aRef); sa = new String[len]; for (int i=0; i<len; i++){ int sRef = getReferenceArrayElement(aRef,i).getValue(); sa[i] = getStringObject(ctx, sRef); } return sa; } else { throw new IllegalArgumentException("not a String[] array: " + aci.getName()); } } else { throw new IllegalArgumentException("not an array reference: " + aci.getName()); } } public Date getDateObject (int objref) { if (objref != MJIEnv.NULL) { ElementInfo ei = getElementInfo(objref); if (ei.getClassInfo().getName().equals("java.util.Date")) { // <2do> this is not complete yet long fastTime = ei.getLongField("fastTime").getValue(); Date d = new Date(fastTime); return d; } else { throw new JPFException("not a Date object reference: " + ei); } } else { return null; } } public Object[] getArgumentArray (FeatureExpr ctx, int argRef) { Object[] args = null; if (argRef == NULL) { return args; } int nArgs = getArrayLength(ctx, argRef); args = new Object[nArgs]; for (int i=0; i<nArgs; i++){ int aref = getReferenceArrayElement(argRef,i).getValue(); ClassInfo ci = getClassInfo(aref); String clsName = ci.getName(); if (clsName.equals("java.lang.Boolean")){ args[i] = getBooleanField(aref,"value").getValue(); } else if (clsName.equals("java.lang.Integer")){ args[i] = getIntField(aref,"value").getValue(); } else if (clsName.equals("java.lang.Double")){ args[i] = getDoubleField(aref,"value").getValue(); } else if (clsName.equals("java.lang.String")){ args[i] = getStringObject(ctx, aref); } } return args; } public Boolean getBooleanObject (int objref){ return getBooleanField(objref, "value").getValue();// TODO jens } public Byte getByteObject (int objref){ return getByteField(objref, "value").getValue(); } public Character getCharObject (int objref){ return getCharField(objref, "value").getValue();// TODO jens } public Short getShortObject (int objref){ return getShortField(objref, "value").getValue();// TODO jens } public Conditional<Integer> getIntegerObject (int objref){ return getIntField(objref, "value"); } public Long getLongObject (int objref){ return getLongField(objref, "value").getValue();// TODO jens } public Float getFloatObject (int objref){ return getFloatField(objref, "value").getValue();// TODO jens } public Double getDoubleObject (int objref){ return getDoubleField(objref, "value").getValue();// TODO jens } // danger - the returned arrays could be used to modify contents of stored objects public Conditional<Byte>[] getByteArrayObject(FeatureExpr ctx, int objref) { ElementInfo ei = getElementInfo(objref); return ei.asByteArray(); } @Deprecated public byte[] getByteArrayObjectDeprecated(FeatureExpr ctx, int objref) { ElementInfo ei = getElementInfo(objref); Conditional<Byte>[] ba = ei.asByteArray(); byte[] a = new byte[ba.length]; for (int i = 0; i < ba.length; i++) { a[i]= ba[i].simplify(ctx).getValue(); } return a; } public Conditional<char[]> getCharArrayObject (int objref) { ElementInfo ei = getElementInfo(objref); return ei.asCharArray(); } public Conditional<Short>[] getShortArrayObject (int objref) { ElementInfo ei = getElementInfo(objref); return ei.asShortArray(); } public int[] getIntArrayObject (FeatureExpr ctx, int objref) {// TODO jens ElementInfo ei = getElementInfo(objref); Conditional<Integer>[] array = ei.asIntArray(); int[] a = new int[array.length]; for (int i = 0; i < array.length; i++) { a[i] = array[i].simplify(ctx).getValue(); } return a; } public Conditional<Long>[] getLongArrayObject (int objref) { ElementInfo ei = getElementInfo(objref); Conditional<Long>[] a = ei.asLongArray(); return a; } public Conditional<Float>[] getFloatArrayObject (int objref) { ElementInfo ei = getElementInfo(objref); Conditional<Float>[] a = ei.asFloatArray(); return a; } @Deprecated public float[] getFloatArrayObjectDeprecated(FeatureExpr ctx, int objref) { ElementInfo ei = getElementInfo(objref); Conditional<Float>[] fa = ei.asFloatArray(); float[] a = new float[fa.length]; for (int i = 0; i < fa.length; i++) { a[i]= fa[i].simplify(ctx).getValue(); } return a; } @Deprecated public double[] getDoubleArrayObjectDeprecated(FeatureExpr ctx, int objref) { ElementInfo ei = getElementInfo(objref); Conditional<Double>[] da = ei.asDoubleArray(); double[] a = new double[da.length]; for (int i = 0; i < da.length; i++) { a[i]= da[i].simplify(ctx).getValue(); } return a; } public Conditional<Double>[] getDoubleArrayObject (int objref) { ElementInfo ei = getElementInfo(objref); return ei.asDoubleArray(); } public Conditional<Boolean>[] getBooleanArrayObject (int objref) { ElementInfo ei = getElementInfo(objref); Conditional<Boolean>[] a = ei.asBooleanArray(); return a; } public Conditional<Integer>[] getReferenceArrayObject (int objref){ ElementInfo ei = getElementInfo(objref); Conditional<Integer>[] a = ei.asReferenceArray(); return a; } /** * NOTE - this call might change the corresponding ElementInfo instance, * don't use after obtaining the ElementInfo in the caller ! */ public boolean isSchedulingRelevantObject(int objref){ if (objref != NULL){ ElementInfo ei = heap.get(objref); ei = ei.getInstanceWithUpdatedSharedness(ti); return ei.isShared(); } return false; } public boolean canLock (int objref) { ElementInfo ei = getElementInfo(objref); return ei.canLock(ti); } public int newBooleanArray (int size) {// TODO jens return heap.newArray(FeatureExprFactory.True(), "Z", size, ti).getObjectRef(); } public int newByteArray (int size) {// TODO jens return heap.newArray(FeatureExprFactory.True(), "B", size, ti).getObjectRef(); } public int newByteArray (FeatureExpr ctx, byte[] buf){// TODO jens ElementInfo eiArray = heap.newArray(ctx, "B", buf.length, ti); for (int i=0; i<buf.length; i++){ eiArray.setByteElement( ctx, i, new One<>(buf[i])); } return eiArray.getObjectRef(); } public int newCharArray (FeatureExpr ctx, int size) {// TODO jens return heap.newArray(ctx, "C", size, ti).getObjectRef(); } public int newCharArray (FeatureExpr ctx, char[] buf){// TODO jens ElementInfo eiArray = heap.newArray(ctx, "C", buf.length, ti); for (int i=0; i<buf.length; i++){ eiArray.setCharElement(ctx, i, new One<>(buf[i])); } return eiArray.getObjectRef(); } public int newShortArray (int size) {// TODO jens return heap.newArray(FeatureExprFactory.True(), "S", size, ti).getObjectRef(); } public int newShortArray (FeatureExpr ctx, short[] buf){// TODO jens ElementInfo eiArray = heap.newArray(FeatureExprFactory.True(), "S", buf.length, ti); for (int i=0; i<buf.length; i++){ eiArray.setShortElement(ctx, i, new One<>(buf[i])); } return eiArray.getObjectRef(); } public int newDoubleArray (int size) {// TODO jens return heap.newArray(FeatureExprFactory.True(), "D", size, ti).getObjectRef(); } public int newDoubleArray (FeatureExpr ctx, double[] buf){ ElementInfo eiArray = heap.newArray(ctx, "D", buf.length, ti); for (int i=0; i<buf.length; i++){ eiArray.setDoubleElement(ctx, i, new One<>(buf[i])); } return eiArray.getObjectRef(); } public int newFloatArray (int size) {// TODO jens return heap.newArray(FeatureExprFactory.True(), "F", size, ti).getObjectRef(); } public int newFloatArray (float[] buf){// TODO jens ElementInfo eiArray = heap.newArray(FeatureExprFactory.True(), "F", buf.length, ti); for (int i=0; i<buf.length; i++){ eiArray.setFloatElement(FeatureExprFactory.True(), i, new One<>(buf[i])); } return eiArray.getObjectRef(); } public int newIntArray (int size) {// TODO jens return heap.newArray(FeatureExprFactory.True(), "I", size, ti).getObjectRef(); } public int newIntArray (FeatureExpr ctx, int[] buf){// TODO jens ElementInfo eiArray = heap.newArray(ctx, "I", buf.length, ti); for (int i=0; i<buf.length; i++){ eiArray.setIntElement( ctx, i, new One<>(buf[i])); } return eiArray.getObjectRef(); } public int newLongArray (int size) {// TODO jens return heap.newArray(FeatureExprFactory.True(), "J", size, ti).getObjectRef(); } public int newLongArray (long[] buf){// TODO jens ElementInfo eiArray = heap.newArray(null, "J", buf.length, ti); for (int i=0; i<buf.length; i++){ eiArray.setLongElement( null, i, new One<>(buf[i])); } return eiArray.getObjectRef(); } public int newObjectArray (String elementClsName, int size) {// TODO jens if (!elementClsName.endsWith(";")) { elementClsName = Types.getTypeSignature(elementClsName, false); } return heap.newArray(FeatureExprFactory.True(), elementClsName, size, ti).getObjectRef(); } /** * check if the ClassInfo is properly initialized * if yes, create a new instance of it but don't call any ctor * if no, throw a ClinitRequired exception */ public int newObject (FeatureExpr ctx, ClassInfo ci) { if (ci.pushRequiredClinits(ctx, ti)){ throw new ClinitRequired(ci); } ElementInfo ei = heap.newObject(ctx, ci, ti); return ei.getObjectRef(); } /** * this creates a new object without checking if the ClassInfo needs * initialization. This is useful in a context that already * is aware and handles re-execution */ public int newObjectOfUncheckedClass (FeatureExpr ctx, ClassInfo ci){ ElementInfo ei = heap.newObject(ctx, ci, ti); return ei.getObjectRef(); } public int newObject (FeatureExpr ctx, String clsName) { ClassInfo ci = ClassLoaderInfo.getCurrentResolvedClassInfo(clsName); if (ci != null){ return newObject(ctx, ci); } else { return NULL; } } public int newString (FeatureExpr ctx, String s) { return newString(ctx, new One<>(s)); } public int newString (FeatureExpr ctx, Conditional<String> s) { if (s instanceof One && s.getValue() == null){ return NULL; } else { return heap.newString(ctx, s, ti).getObjectRef(); } } public int newStringArray (FeatureExpr ctx, String[] a){ int aref = newObjectArray("Ljava/lang/String;", a.length); for (int i=0; i<a.length; i++){ setReferenceArrayElement(ctx, aref, i, new One<>(newString(FeatureExprFactory.True(), new One<>(a[i])))); } return aref; } public int newString (int arrayRef) {// TODO jens String t = getArrayType(arrayRef); String s = null; if ("C".equals(t)) { // character array char[] ca = getCharArrayObject(arrayRef).getValue(); s = new String(ca); } else if ("B".equals(t)) { // byte array byte[] ba = getByteArrayObjectDeprecated(null, arrayRef); s = new String(ba); } if (s == null) { return NULL; } return newString(FeatureExprFactory.True(), new One<>(s)); } public String format (FeatureExpr ctx, int fmtRef, int argRef){ String format = getStringObject(ctx, fmtRef); int len = argRef == MJIEnv.NULL ? 0 : getArrayLength(ctx, argRef); Object[] arg = new Object[len]; for (int i=0; i<len; i++){ int ref = getReferenceArrayElement(argRef,i).simplify(ctx).getValue(); if (ref != NULL) { String clsName = getClassName(ref); if (clsName.equals("java.lang.String")) { arg[i] = getStringObject(ctx, ref); } else if (clsName.equals("java.lang.Byte")) { arg[i] = getByteObject(ref); } else if (clsName.equals("java.lang.Char")) { arg[i] = getCharObject(ref); } else if (clsName.equals("java.lang.Short")) { arg[i] = getShortObject(ref); } else if (clsName.equals("java.lang.Integer")) { arg[i] = createSimpleObj(getIntegerObject(ref), ctx); } else if (clsName.equals("java.lang.Long")) { arg[i] = getLongObject(ref); } else if (clsName.equals("java.lang.Float")) { arg[i] = getFloatObject(ref); } else if (clsName.equals("java.lang.Double")) { arg[i] = getDoubleObject(ref); } else { // need a toString() here arg[i] = "??"; } } } return String.format(format,arg); } private static Object createSimpleObj(Conditional<?> c, FeatureExpr ctx) { c = c.simplify(ctx); if (c instanceof One) { return c.getValue(); } return c; } public String format (FeatureExpr ctx,Locale l, int fmtRef, int argRef){ String format = getStringObject(ctx, fmtRef); int len = getArrayLength(ctx, argRef); Object[] arg = new Object[len]; for (int i=0; i<len; i++){ int ref = getReferenceArrayElement(argRef,i).getValue(); if (ref != NULL) { String clsName = getClassName(ref); if (clsName.equals("java.lang.String")) { arg[i] = getStringObject(ctx, ref); } else if (clsName.equals("java.lang.Byte")) { arg[i] = getByteObject(ref); } else if (clsName.equals("java.lang.Char")) { arg[i] = getCharObject(ref); } else if (clsName.equals("java.lang.Short")) { arg[i] = getShortObject(ref); } else if (clsName.equals("java.lang.Integer")) { arg[i] = createSimpleObj(getIntegerObject(ref), ctx); } else if (clsName.equals("java.lang.Long")) { arg[i] = getLongObject(ref); } else if (clsName.equals("java.lang.Float")) { arg[i] = getFloatObject(ref); } else if (clsName.equals("java.lang.Double")) { arg[i] = getDoubleObject(ref); } else { // need a toString() here arg[i] = "??"; } } } return String.format(l,format,arg); } public int newBoolean (boolean b){// TODO jens return getStaticReferenceField("java.lang.Boolean", b ? "TRUE" : "FALSE"); } public int newInteger (FeatureExpr ctx, Conditional<Integer> n){ ElementInfo ei = heap.newObject(ctx, ClassLoaderInfo.getSystemResolvedClassInfo("java.lang.Integer"), ti); ei.setIntField(ctx, "value",n); return ei.getObjectRef(); } public int newLong (FeatureExpr ctx, Conditional<Long> l){ ElementInfo ei = heap.newObject(ctx, ClassLoaderInfo.getSystemResolvedClassInfo("java.lang.Long"), ti); ei.setLongField(ctx, "value", l); return ei.getObjectRef(); } public int newDouble (FeatureExpr ctx, Conditional<Double> d){ ElementInfo ei = heap.newObject(ctx, ClassLoaderInfo.getSystemResolvedClassInfo("java.lang.Double"), ti); ei.setDoubleField(ctx,"value", d); return ei.getObjectRef(); } public int newFloat (FeatureExpr ctx, Conditional<Float> f){ ElementInfo ei = heap.newObject(ctx, ClassLoaderInfo.getSystemResolvedClassInfo("java.lang.Float"), ti); ei.setFloatField(ctx,"value", f); return ei.getObjectRef(); } public int newByte (FeatureExpr ctx, Conditional<Byte> b){ ElementInfo ei = heap.newObject(ctx, ClassLoaderInfo.getSystemResolvedClassInfo("java.lang.Byte"), ti); ei.setByteField(ctx,"value", b); return ei.getObjectRef(); } public int newShort (FeatureExpr ctx, Conditional<Short> s){ ElementInfo ei = heap.newObject(ctx, ClassLoaderInfo.getSystemResolvedClassInfo("java.lang.Short"), ti); ei.setShortField(ctx,"value", s); return ei.getObjectRef(); } public int newCharacter (FeatureExpr ctx, Conditional<Character> c){ ElementInfo ei = heap.newObject(ctx, ClassLoaderInfo.getSystemResolvedClassInfo("java.lang.Character"), ti); ei.setCharField(ctx, "value", c); return ei.getObjectRef(); } public void notify (FeatureExpr ctx, int objref) { // objref can't be NULL since the corresponding INVOKE would have failed ElementInfo ei = getModifiableElementInfo(objref); notify(ctx, ei); } public void notify (FeatureExpr ctx, ElementInfo ei) { if (!ei.isLockedBy(ti)){ throwException(ctx, "java.lang.IllegalMonitorStateException", "un-synchronized notify"); return; } ei.notifies(getSystemState(), ti); } public void notifyAll (FeatureExpr ctx, int objref) { // objref can't be NULL since the corresponding INVOKE would have failed ElementInfo ei = getElementInfo(objref); notifyAll(ctx, ei); } public void notifyAll (FeatureExpr ctx, ElementInfo ei) { if (!ei.isLockedBy(ti)){ throwException(ctx, "java.lang.IllegalMonitorStateException", "un-synchronized notifyAll"); return; } ei.notifiesAll(); } public void registerPinDown(int objref){ vm.getHeap().registerPinDown(objref); } public void releasePinDown(int objref){ vm.getHeap().releasePinDown(objref); } /** * use this whenever a peer performs an operation on a class that might not be initialized yet * Do a repeatInvocation() in this case */ public boolean requiresClinitExecution(FeatureExpr ctx, ClassInfo ci) { return ci.pushRequiredClinits(ctx, ti); } /** * repeat execution of the instruction that caused a native method call * NOTE - this does NOT mean it's the NEXT executed insn, since the native method * might have pushed direct call frames on the stack before asking us to repeat it. */ public void repeatInvocation () { repeat = true; } public boolean isInvocationRepeated() { return repeat; } public boolean setNextChoiceGenerator (ChoiceGenerator<?> cg){ return vm.getSystemState().setNextChoiceGenerator(cg); } public void setMandatoryNextChoiceGenerator(ChoiceGenerator<?> cg, String failMsg){ vm.getSystemState().setMandatoryNextChoiceGenerator(cg, failMsg); } public SchedulerFactory getSchedulerFactory(){ return vm.getSchedulerFactory(); } public ChoiceGenerator<?> getChoiceGenerator () { return vm.getSystemState().getChoiceGenerator(); } // note this only makes sense if we actually do return something public void setReturnAttribute (Object attr) { returnAttr = attr; } /** * return attr list of all arguments. Use ObjectList to retrieve values * from this list * * NOTE - this can only be called from a native method context, since * otherwise the top frame is the callee */ public Object[] getArgAttributes () { StackFrame caller = getCallerStackFrame(); return caller.getArgumentAttrs(mi); } public Object getReturnAttribute() { return returnAttr; } // if any of the next methods is called from the bottom // half of a CG method, you might want to check if another thread // or a listener has already set an exception you don't want to override // (this is for instance used in Thread.stop()) public void throwException (int xRef){ assert isInstanceOf(xRef, "java.lang.Throwable"); exceptionRef = xRef; } public void throwException (FeatureExpr ctx, String clsName) { ClassInfo ciX = ClassInfo.getInitializedClassInfo(null, clsName, ti); assert ciX.isInstanceOf("java.lang.Throwable"); exceptionRef = ti.createException(ctx, ciX, null, NULL); } public void throwException (FeatureExpr ctx, String clsName, String details) { ClassInfo ciX = ClassInfo.getInitializedClassInfo(ctx, clsName, ti); assert ciX.isInstanceOf("java.lang.Throwable"); exceptionRef = ti.createException(ctx, ciX, details, NULL); } public void throwAssertion (FeatureExpr ctx, String details) { throwException(ctx, "java.lang.AssertionError", details); } public void throwInterrupt(FeatureExpr ctx){ throwException(ctx, "java.lang.InterruptedException"); } public void stopThread(FeatureExpr ctx){ stopThreadWithException(ctx, MJIEnv.NULL); } public void stopThreadWithException (FeatureExpr ctx, int xRef){ // this will call throwException(xRef) with the proper Throwable ti.setStopped(ctx, xRef); } void setCallEnvironment (MethodInfo mi) { this.mi = mi; if (mi != null){ ciMth = mi.getClassInfo(); } else { //ciMth = null; //mi = null; } repeat = false; returnAttr = null; // we should NOT reset exceptionRef here because it might have been set // at the beginning of the transition. It gets reset upon return from the // native method //exceptionRef = NULL; } void clearCallEnvironment () { setCallEnvironment(null); } ElementInfo getStaticElementInfo (int clsObjRef) { ClassInfo ci = getReferredClassInfo( FeatureExprFactory.True(), clsObjRef); if (ci != null) { return ci.getStaticElementInfo(); } return null; } ElementInfo getModifiableStaticElementInfo (int clsObjRef) { ClassInfo ci = getReferredClassInfo( FeatureExprFactory.True(), clsObjRef); if (ci != null) { return ci.getModifiableStaticElementInfo(); } return null; } ClassInfo getClassInfo () { return ciMth; } public ClassInfo getReferredClassInfo (FeatureExpr ctx, int clsObjRef) { if (ctx == null) { // TODO remove ctx = FeatureExprFactory.True(); } ElementInfo ei = getElementInfo(clsObjRef); if (ei.getClassInfo().getName().equals("java.lang.Class")) { int ciId = ei.getIntField(ClassInfo.ID_FIELD).simplify(ctx).getValue(); int clref = ei.getReferenceField("classLoader").getValue(); ElementInfo eiCl = getElementInfo(clref); int cliId = eiCl.getIntField(ClassLoaderInfo.ID_FIELD).simplify(ctx).getValue(); ClassLoaderInfo cli = getVM().getClassLoader(cliId); ClassInfo referredCi = cli.getClassInfo(ciId); return referredCi; } else { throw new JPFException("not a java.lang.Class object: " + ei); } } public ClassInfo getClassInfo (int objref) { ElementInfo ei = getElementInfo(objref); if (ei != null){ return ei.getClassInfo(); } else { return null; } } public String getClassName (int objref) { return getClassInfo(objref).getName(); } public Heap getHeap () { return vm.getHeap(); } public ElementInfo getElementInfo (int objref) { return heap.get(objref); } public ElementInfo getModifiableElementInfo (int objref) { return heap.getModifiable(objref); } public int getStateId () { return VM.getVM().getStateId(); } void clearException(){ exceptionRef = MJIEnv.NULL; } public int peekException () { return exceptionRef; } public int popException () { int ret = exceptionRef; exceptionRef = NULL; return ret; } public boolean hasException(){ return (exceptionRef != NULL); } public boolean hasPendingInterrupt(){ return (exceptionRef != NULL && isInstanceOf(exceptionRef, "java.lang.InterruptedException")); } //-- time is managed by the VM public long currentTimeMillis(){ return vm.currentTimeMillis(); } public long nanoTime(){ return vm.nanoTime(); } //--- those are not public since they refer to JPF internals public KernelState getKernelState () { return VM.getVM().getKernelState(); } public MethodInfo getMethodInfo () { return mi; } public Instruction getInstruction () { return ti.getPC().getValue(); } /** * It returns the ClassLoaderInfo corresponding to the given classloader object * reference */ public ClassLoaderInfo getClassLoaderInfo(int clObjRef) { if(clObjRef == MJIEnv.NULL) { return null; } int cliId = heap.get(clObjRef).getIntField(ClassLoaderInfo.ID_FIELD).getValue(); return getVM().getClassLoader(cliId); } // <2do> that's not correct - it should return the current SystemClassLoader, NOT the startup SystemClassLoader // (we can instantiate them explicitly) public ClassLoaderInfo getSystemClassLoaderInfo() { return ti.getSystemClassLoaderInfo(); } public SystemState getSystemState () { return ti.getVM().getSystemState(); } public ThreadInfo getThreadInfo () { return ti; } /** * NOTE - callers have to be prepared this might return null in case * the thread got already terminated */ public ThreadInfo getThreadInfoForId (int id){ return vm.getThreadList().getThreadInfoForId(id); } public ThreadInfo getLiveThreadInfoForId (int id){ ThreadInfo ti = vm.getThreadList().getThreadInfoForId(id); if (ti != null && ti.isAlive()){ return ti; } return null; } /** * NOTE - callers have to be prepared this might return null in case * the thread got already terminated */ public ThreadInfo getThreadInfoForObjRef (int id){ return vm.getThreadList().getThreadInfoForObjRef(id); } public ThreadInfo getLiveThreadInfoForObjRef (int id){ ThreadInfo ti = vm.getThreadList().getThreadInfoForObjRef(id); if (ti != null && ti.isAlive()){ return ti; } return null; } public ThreadInfo[] getLiveThreads(){ return getVM().getLiveThreads(); } // <2do> - naming? not very intuitive void lockNotified (int objref) { ElementInfo ei = getModifiableElementInfo(objref); ei.lockNotified(ti); } void initAnnotationProxyField (FeatureExpr ctx, int proxyRef, FieldInfo fi, Object v) throws ClinitRequired { String fname = fi.getName(); String ftype = fi.getType(); if (v instanceof String){ setReferenceField(ctx, proxyRef, fname, newString(FeatureExprFactory.True(), new One<>((String)v))); } else if (v instanceof Boolean){ setBooleanField(ctx, proxyRef, fname, new One<>((Boolean)v)); } else if (v instanceof Integer){ setIntField(ctx, proxyRef, fname, new One<>((Integer)v)); } else if (v instanceof Long){ setLongField(ctx, proxyRef, fname, new One<>((Long)v)); } else if (v instanceof Float){ setFloatField(ctx, proxyRef, fname, new One<>((Float)v)); } else if (v instanceof Short){ setShortField(ctx, proxyRef, fname, new One<>((Short)v)); } else if (v instanceof Character){ setCharField(ctx, proxyRef, fname, new One<>((Character)v)); } else if (v instanceof Byte){ setByteField(ctx, proxyRef, fname, new One<>((Byte)v)); } else if (v instanceof Double){ setDoubleField(ctx, proxyRef, fname, new One<>((Double)v)); } else if (v instanceof AnnotationInfo.EnumValue){ // an enum constant AnnotationInfo.EnumValue ev = (AnnotationInfo.EnumValue)v; String eCls = ev.getEnumClassName(); String eConst = ev.getEnumConstName(); ClassInfo eci = ClassLoaderInfo.getCurrentResolvedClassInfo(eCls); if (!eci.isInitialized()){ throw new ClinitRequired(eci); } StaticElementInfo sei = eci.getStaticElementInfo(); int eref = sei.getReferenceField(eConst).getValue(); setReferenceField(ctx, proxyRef, fname, eref); } else if (v instanceof AnnotationInfo.ClassValue){ // a class String clsName = v.toString(); ClassInfo cci = ClassLoaderInfo.getCurrentResolvedClassInfo(clsName); // <2do> should throw ClassNotFoundError here if cci is null if (!cci.isInitialized()){ throw new ClinitRequired(cci); } int cref = cci.getClassObjectRef(); setReferenceField(ctx, proxyRef, fname, cref); } else if (v.getClass().isArray()){ // ..or arrays thereof Object[] a = (Object[])v; int aref = NULL; if (ftype.equals("java.lang.String[]")){ aref = newObjectArray("Ljava/lang/String;", a.length); for (int i=0; i<a.length; i++){ setReferenceArrayElement(ctx,aref,i, new One<>(newString(FeatureExprFactory.True(), new One<>(a[i].toString())))); } } else if (ftype.equals("int[]")){ aref = newIntArray(a.length); for (int i=0; i<a.length; i++){ setIntArrayElement(ctx,aref,i, new One<>((Integer)a[i])); } } else if (ftype.equals("boolean[]")){ aref = newBooleanArray(a.length); for (int i=0; i<a.length; i++){ setBooleanArrayElement(ctx,aref,i, new One<>((Boolean)a[i])); } } else if (ftype.equals("long[]")){ aref = newLongArray(a.length); for (int i=0; i<a.length; i++){ setLongArrayElement(ctx,aref,i, new One<>(((Long)a[i]))); } } else if (ftype.equals("double[]")){ aref = newDoubleArray(a.length); for (int i=0; i<a.length; i++){ setDoubleArrayElement(ctx,aref,i, new One<>(((Double)a[i]))); } } else if (ftype.equals("java.lang.Class[]")){ aref = newObjectArray("java.lang.Class", a.length); for (int i=0; i<a.length; i++){ String clsName = ((AnnotationInfo.ClassValue)a[i]).getName(); ClassInfo cci = ClassLoaderInfo.getCurrentResolvedClassInfo(clsName); if (!cci.isInitialized()){ throw new ClinitRequired(cci); } int cref = cci.getClassObjectRef(); setReferenceArrayElement(ctx,aref,i, new One<>(cref)); } } if (aref != NULL){ setReferenceField(ctx, proxyRef, fname, aref); } else { throwException(ctx, "AnnotationElement type not supported: " + ftype); } } else { throwException(ctx, "AnnotationElement type not supported: " + ftype); } } int newAnnotationProxy (FeatureExpr ctx, ClassInfo aciProxy, AnnotationInfo ai) throws ClinitRequired { int proxyRef = newObject(ctx, aciProxy); // init fields of the new object from the AnnotationInfo for (AnnotationInfo.Entry e : ai.getEntries()){ Object v = e.getValue(); String fname = e.getKey(); FieldInfo fi = aciProxy.getInstanceField(fname); initAnnotationProxyField(ctx, proxyRef, fi, v); } return proxyRef; } int newAnnotationProxies (FeatureExpr ctx, AnnotationInfo[] ai) throws ClinitRequired { if ((ai != null) && (ai.length > 0)){ int aref = newObjectArray("Ljava/lang/annotation/Annotation;", ai.length); for (int i=0; i<ai.length; i++){ ClassInfo aci = ClassLoaderInfo.getCurrentResolvedClassInfo(ai[i].getName()); ClassInfo aciProxy = aci.getAnnotationProxy(); int ar = newAnnotationProxy(ctx, aciProxy, ai[i]); setReferenceArrayElement(ctx, aref, i, new One<>(ar)); } return aref; } else { // on demand init (not too many programs use annotation reflection) int aref = getStaticReferenceField("java.lang.Class", "emptyAnnotations"); if (aref == NULL) { aref = newObjectArray("Ljava/lang/annotation/Annotation;", 0); setStaticReferenceField(ctx, "java.lang.Class", "emptyAnnotations", aref); } return aref; } } public void handleClinitRequest (FeatureExpr ctx, ClassInfo ci) { ThreadInfo ti = getThreadInfo(); // NOTE: we have to repeat no matter what, since this is called from // a handler context (if we only had to create a class object w/o // calling clinit, we can't just go on) ci.pushRequiredClinits(ctx, ti); repeatInvocation(); } public StackFrame getCallerStackFrame() { // since native methods are now executed within their own stack frames // we provide a little helper to get the caller return ti.getLastNonSyntheticStackFrame(); } public StackFrame getModifiableCallerStackFrame() { // since native methods are now executed within their own stack frames // we provide a little helper to get the caller return ti.getModifiableLastNonSyntheticStackFrame(); } public int valueOfBoolean(boolean b) { return BoxObjectCacheManager.valueOfBoolean(ti, b); } public int valueOfByte(FeatureExpr ctx, byte b) { return BoxObjectCacheManager.valueOfByte(ctx, ti, b); } public int valueOfCharacter(FeatureExpr ctx, char c) { return BoxObjectCacheManager.valueOfCharacter(ctx, ti, c); } public int valueOfShort(FeatureExpr ctx, short s) { return BoxObjectCacheManager.valueOfShort(ctx, ti, s); } public Conditional<Integer> valueOfInteger(FeatureExpr ctx, int i) { return BoxObjectCacheManager.valueOfInteger(ctx, ti, i); } public Conditional<Integer> valueOfInteger(FeatureExpr ctx, Conditional<Integer> i) { return i.mapf(ctx, new BiFunction<FeatureExpr, Integer, Conditional<Integer>>() { @Override public Conditional<Integer> apply(FeatureExpr ctx, Integer i) { return BoxObjectCacheManager.valueOfInteger(ctx, ti, i); } }); } public int valueOfLong(FeatureExpr ctx, long l) { return BoxObjectCacheManager.valueOfLong(ctx, ti, l); } /** * Contains objects created and handles by the host JVM. */ private static HashMap<Integer, Object> JVMObjects = new HashMap<>(); /** * Add a HostJVM object. * @param objref The object reference of VarexJ * @param object The object of the HostJVM */ public void addJVMObject(int objref, Object object) { JVMObjects.put(objref, object); } /** * Get a HostJVM object. * @param objref The object reference of VarexJ * @return The object of the HostJVM */ public Object getJVMObject(int objref) { return JVMObjects.get(objref); } /** * Remove a HostJVM object. * @param objref The object reference of VarexJ */ public void removeJVMObject(int objref) {// TODO add to garbage collection JVMObjects.remove(objref); } }