//
// Copyright (C) 2012 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.function.BiFunction;
import cmu.conditional.Conditional;
import cmu.conditional.One;
import de.fosd.typechef.featureexpr.FeatureExpr;
import de.fosd.typechef.featureexpr.FeatureExprFactory;
/**
* @author Nastaran Shafiei <nastaran.shafiei@gmail.com>
*
* Cache management implementation for the types Boolean, Byte,
* Character, Short, Integer, Long. The references to the caches are in
* the class classes/gov/nasa/jpf/BoxObjectCaches.
*
* All the caches, except Boolean, are initialized on the first
* invocation of valueOf(), and they all exempt from garbage collection.
*
* NOTE: All classes obtained from getResolvedClassInfo in
* BoxObjectCacheManager are safe, and there is no need to check if they
* are initialized. The wrappers and BoxObjectCaches are initialized in
* VM.intialize(), and there are no clinit for array classes.
*
* NOTE: the initXCache allocations are system allocations, whereas the
* valueOfX() allocations are rooted in SUT code
*/
public class BoxObjectCacheManager {
private static final String MODEL_CLASS = "gov.nasa.jpf.BoxObjectCaches";
private static final int ANCHOR = BoxObjectCacheManager.class.getName().hashCode();
// cache default bounds
private static int defLow = -128;
private static int defHigh = 127;
public static int valueOfBoolean (ThreadInfo ti, boolean b) {
ClassInfo cls = ClassLoaderInfo.getSystemResolvedClassInfo("java.lang.Boolean");
int boolObj;
if (b) {
boolObj = cls.getStaticElementInfo().getReferenceField("TRUE").getValue();
} else {
boolObj = cls.getStaticElementInfo().getReferenceField("FALSE").getValue();
}
return boolObj;
}
// Byte cache bounds
private static byte byteLow;
private static byte byteHigh;
public static int initByteCache (FeatureExpr ctx, ThreadInfo ti) {
byteLow = (byte) ti.getVM().getConfig().getInt("vm.cache.low_byte", defLow);
byteHigh = (byte) ti.getVM().getConfig().getInt("vm.cache.high_byte", defHigh);
int n = (byteHigh - byteLow) + 1;
Heap heap = ti.getHeap();
ElementInfo eiArray = heap.newSystemArray("Ljava/lang/Byte", n, ti, ANCHOR);
int arrayRef = eiArray.getObjectRef();
ClassInfo ci = ClassLoaderInfo.getSystemResolvedClassInfo("java.lang.Byte");
byte val = byteLow;
for (int i = 0; i < n; i++) {
ElementInfo eiByte = heap.newSystemObject(ctx, ci, ti, ANCHOR);
eiByte.setByteField(ctx, "value", One.valueOf(val++));
eiArray.setReferenceElement(ctx, i, new One<>(eiByte.getObjectRef()));
}
ClassInfo cacheClass = ClassLoaderInfo.getSystemResolvedClassInfo(MODEL_CLASS);
cacheClass.getModifiableStaticElementInfo().setReferenceField(ctx, "byteCache", new One<>(arrayRef));
return arrayRef;
}
public static int valueOfByte (FeatureExpr ctx, ThreadInfo ti, byte b) {
ClassInfo cacheClass = ClassLoaderInfo.getSystemResolvedClassInfo(MODEL_CLASS);
int byteCache = cacheClass.getStaticElementInfo().getReferenceField("byteCache").getValue();
if (byteCache == MJIEnv.NULL) { // initializing the cache on demand
byteCache = initByteCache(ctx, ti);
}
if (b >= byteLow && b <= byteHigh) { return ti.getElementInfo(byteCache).getReferenceElement(b - byteLow).getValue(); }
ClassInfo ci = ClassLoaderInfo.getSystemResolvedClassInfo("java.lang.Byte");
ElementInfo eiByte = ti.getHeap().newObject(ctx, ci, ti);
eiByte.setByteField(ctx, "value", new One<>(b));
return eiByte.getObjectRef();
}
// Character cache bound
private static int charHigh;
public static int initCharCache (FeatureExpr ctx, ThreadInfo ti) {
charHigh = ti.getVM().getConfig().getInt("vm.cache.high_char", defHigh);
int n = charHigh + 1;
Heap heap = ti.getHeap();
ElementInfo eiArray = heap.newSystemArray("Ljava/lang/Character", n, ti, ANCHOR);
int arrayRef = eiArray.getObjectRef();
ClassInfo ci = ClassLoaderInfo.getSystemResolvedClassInfo("java.lang.Character");
for (int i = 0; i < n; i++) {
ElementInfo eiChar = heap.newSystemObject(ctx, ci, ti, ANCHOR);
eiChar.setCharField(ctx, "value", One.valueOf((char) i));
eiArray.setReferenceElement(ctx, i, new One<>(eiChar.getObjectRef()));
}
ClassInfo cacheClass = ClassLoaderInfo.getSystemResolvedClassInfo(MODEL_CLASS);
cacheClass.getModifiableStaticElementInfo().setReferenceField(ctx, "charCache", new One<>(arrayRef));
return arrayRef;
}
public static int valueOfCharacter (FeatureExpr ctx, ThreadInfo ti, char c) {
ClassInfo cacheClass = ClassLoaderInfo.getSystemResolvedClassInfo(MODEL_CLASS);
int charCache = cacheClass.getStaticElementInfo().getReferenceField("charCache").getValue();
if (charCache == MJIEnv.NULL) { // initializing the cache on demand
charCache = initCharCache(ctx, ti);
}
if (c >= 0 && c <= charHigh) { return ti.getElementInfo(charCache).getReferenceElement(c).getValue(); }
ClassInfo ci = ClassLoaderInfo.getSystemResolvedClassInfo("java.lang.Character");
ElementInfo eiChar = ti.getHeap().newObject(ctx, ci, ti);
eiChar.setCharField(ctx, "value", new One<>(c));
return eiChar.getObjectRef();
}
// Short cache bounds
private static short shortLow;
private static short shortHigh;
public static int initShortCache (FeatureExpr ctx, ThreadInfo ti) {
ctx = FeatureExprFactory.True();
shortLow = (short) ti.getVM().getConfig().getInt("vm.cache.low_short", defLow);
shortHigh = (short) ti.getVM().getConfig().getInt("vm.cache.high_short", defHigh);
int n = (shortHigh - shortLow) + 1;
Heap heap = ti.getHeap();
ElementInfo eiArray = heap.newSystemArray("Ljava/lang/Short", n, ti, ANCHOR);
int arrayRef = eiArray.getObjectRef();
ClassInfo ci = ClassLoaderInfo.getSystemResolvedClassInfo("java.lang.Short");
short val = shortLow;
for (int i = 0; i < n; i++) {
ElementInfo eiShort = heap.newSystemObject(ctx, ci, ti, ANCHOR);
eiShort.setShortField(ctx, "value", new One<>(val++));
eiArray.setReferenceElement(ctx, i, new One<>(eiShort.getObjectRef()));
}
ClassInfo cacheClass = ClassLoaderInfo.getSystemResolvedClassInfo(MODEL_CLASS);
cacheClass.getModifiableStaticElementInfo().setReferenceField(ctx, "shortCache", new One<>(arrayRef));
return arrayRef;
}
public static int valueOfShort (FeatureExpr ctx, ThreadInfo ti, short s) {
ClassInfo cacheClass = ClassLoaderInfo.getSystemResolvedClassInfo(MODEL_CLASS);
int shortCache = cacheClass.getStaticElementInfo().getReferenceField("shortCache").simplify(ctx).getValue();
if (shortCache == MJIEnv.NULL) { // initializing the cache on demand
shortCache = initShortCache(FeatureExprFactory.True(), ti);
}
if (s >= shortLow && s <= shortHigh) { return ti.getElementInfo(shortCache).getReferenceElement(s - shortLow).simplify(ctx).getValue(); }
ClassInfo ci = ClassLoaderInfo.getSystemResolvedClassInfo("java.lang.Short");
ElementInfo eiShort = ti.getHeap().newObject(ctx, ci, ti);
eiShort.setShortField(ctx, "value", new One<>(s));
return eiShort.getObjectRef();
}
// Integer cache bounds
private static int intLow;
private static int intHigh;
public static int initIntCache (FeatureExpr ctx, ThreadInfo ti) {
intLow = ti.getVM().getConfig().getInt("vm.cache.low_int", defLow);
intHigh = ti.getVM().getConfig().getInt("vm.cache.high_int", defHigh);
int n = (intHigh - intLow) + 1;
Heap heap = ti.getHeap();
ElementInfo eiArray = heap.newSystemArray("Ljava/lang/Integer", n, ti, ANCHOR);
int arrayRef = eiArray.getObjectRef();
ClassInfo ci = ClassLoaderInfo.getSystemResolvedClassInfo("java.lang.Integer");
for (int i = 0; i < n; i++) {
ElementInfo eiInteger = heap.newSystemObject(ctx, ci, ti, ANCHOR);
eiInteger.setIntField(ctx, "value", One.valueOf(i + intLow));
eiArray.setReferenceElement(ctx, i, new One<>(eiInteger.getObjectRef()));
}
ClassInfo cacheClass = ClassLoaderInfo.getSystemResolvedClassInfo(MODEL_CLASS);
cacheClass.getModifiableStaticElementInfo().setReferenceField(ctx, "intCache", new One<>(arrayRef));
return arrayRef;
}
public static Conditional<Integer> valueOfInteger (FeatureExpr ctx, final ThreadInfo ti, final int i) {
ClassInfo cacheClass = ClassLoaderInfo.getSystemResolvedClassInfo(MODEL_CLASS);
Conditional<Integer> intCache = cacheClass.getStaticElementInfo().getReferenceField("intCache").simplify(ctx);
return intCache.mapf(ctx, new BiFunction<FeatureExpr, Integer, Conditional<Integer>>() {
@Override
public Conditional<Integer> apply(FeatureExpr ctx, Integer intCache) {
if (intCache == MJIEnv.NULL) { // initializing the cache on demand
intCache = initIntCache(ctx, ti);
}
if (i >= intLow && i <= intHigh) { return new One<>(ti.getElementInfo(intCache).getReferenceElement(i - intLow).simplify(ctx).getValue()); }
ClassInfo ci = ClassLoaderInfo.getSystemResolvedClassInfo("java.lang.Integer");
ElementInfo eiInteger = ti.getHeap().newObject(ctx, ci, ti);
eiInteger.setIntField(ctx, "value", new One<>(i));
return new One<>(eiInteger.getObjectRef());
}
});
}
// Long cache bounds
private static int longLow;
private static int longHigh;
public static int initLongCache (FeatureExpr ctx, ThreadInfo ti) {
longLow = ti.getVM().getConfig().getInt("vm.cache.low_long", defLow);
longHigh = ti.getVM().getConfig().getInt("vm.cache.high_long", defHigh);
int n = (longHigh - longLow) + 1;
Heap heap = ti.getHeap();
ElementInfo eiArray = heap.newSystemArray("Ljava/lang/Long", n, ti, ANCHOR);
int arrayRef = eiArray.getObjectRef();
ClassInfo ci = ClassLoaderInfo.getSystemResolvedClassInfo("java.lang.Long");
for (int i = 0; i < n; i++) {
ElementInfo eiLong = heap.newSystemObject(ctx, ci, ti, ANCHOR);
eiLong.setLongField(ctx, "value", new One<>((long) (i + longLow)));
eiArray.setReferenceElement(ctx, i, new One<>(eiLong.getObjectRef()));
}
ClassInfo cacheClass = ClassLoaderInfo.getSystemResolvedClassInfo(MODEL_CLASS);
cacheClass.getModifiableStaticElementInfo().setReferenceField(ctx, "longCache", new One<>(arrayRef));
return arrayRef;
}
public static int valueOfLong (FeatureExpr ctx, ThreadInfo ti, long l) {
ClassInfo cacheClass = ClassLoaderInfo.getSystemResolvedClassInfo(MODEL_CLASS);
int longCache = cacheClass.getStaticElementInfo().getReferenceField("longCache").getValue();
if (longCache == MJIEnv.NULL) { // initializing the cache on demand
longCache = initLongCache(ctx, ti);
}
if (l >= longLow && l <= longHigh) { return ti.getElementInfo(longCache).getReferenceElement((int) l - longLow).simplify(ctx).getValue(); }
ClassInfo ci = ClassLoaderInfo.getSystemResolvedClassInfo("java.lang.Long");
ElementInfo eiLong = ti.getHeap().newObject(ctx, ci, ti);
eiLong.setLongField(ctx, "value", new One<>(l));
return eiLong.getObjectRef();
}
}