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.Config;
21 import gov.nasa.jpf.ConfigChangeListener;
22 import gov.nasa.jpf.JPFException;
23 import gov.nasa.jpf.annotation.MJI;
24 import gov.nasa.jpf.vm.JPF_gov_nasa_jpf_vm_Verify;
25 import gov.nasa.jpf.vm.MJIEnv;
26 import gov.nasa.jpf.vm.NativePeer;
28 import java.lang.reflect.Field;
29 import java.util.Random;
30 import java.util.concurrent.atomic.AtomicLong;
32 import sun.misc.Unsafe;
35 * MJI NativePeer class for java.util.Random library abstraction
37 * model - peer delegation is done via restoring a singleton, which unfortunately
38 * has to resort to the rather nasty Unsafe mechanism because the required
39 * random internals are private. We could use per-instance native objects
40 * stored as object attributes, but that would only partly solve the problem
41 * because we still would have to backtrack the internal state of such objects
43 @SuppressWarnings("sunapi")
44 public class JPF_java_util_Random extends NativePeer {
46 static class Delegatee extends Random {
48 public int next (int nBits){
49 return super.next(nBits);
53 // we need this because cg.enumerate_random might be set on demand
54 static class ConfigListener implements ConfigChangeListener {
55 JPF_java_util_Random nativeRandom;
57 public ConfigListener(JPF_java_util_Random nativeRandom) {
58 this.nativeRandom = nativeRandom;
62 public void propertyChanged(Config config, String key, String oldValue, String newValue) {
63 if ("cg.enumerate_random".equals(key)) {
64 nativeRandom.setEnumerateRandom(config);
69 public void jpfRunTerminated(Config config){
70 config.removeChangeListener(this);
74 boolean enumerateRandom;
76 // those are only used if enumerateRandom is not set, i.e. we delegate to the host VM
77 boolean reproducibleRandom;
79 int[] defaultIntSet; // in case we have an nextInt(), i.e. an unspecified upper boundary
80 long[] defaultLongSet;
81 double[] defaultDoubleSet;
82 float[] defaultFloatSet;
84 // since peer methods are atomic, we just keep one delegator instead of per-object,
85 // which would have to rely on attributes and still require storing/restoring
86 // the seed state with nasty Unsafe
87 static Delegatee delegatee = new Delegatee();
89 // this is bad stuff we need to set/retrieve the Random.seed value. We only have
90 // a choice between a rock and a hard place here - either we depend on this
91 // field and sun.misc.Unsafe, or we duplicate the algorithms. The hard place
92 // seems worse than the rock
93 private static Unsafe unsafe;
94 private static long seedFieldOffset;
98 // Unsafe.getUnsafe() can only be called from a SystemClassLoaderContext
99 Field singletonField = Unsafe.class.getDeclaredField("theUnsafe");
100 singletonField.setAccessible(true);
101 unsafe = (Unsafe)singletonField.get(null);
103 seedFieldOffset = unsafe.objectFieldOffset(Random.class.getDeclaredField("seed"));
104 } catch (Exception ex) {
105 throw new JPFException("cannot access java.util.Random internals: " + ex);
109 private static void setNativeSeed (Random rand, long seed) {
110 AtomicLong al = (AtomicLong) unsafe.getObject(rand, seedFieldOffset);
114 private static long getNativeSeed (Random rand){
115 AtomicLong al = (AtomicLong) unsafe.getObject(rand, seedFieldOffset);
116 return al.longValue();
119 public JPF_java_util_Random (Config conf) {
120 setEnumerateRandom(conf);
121 conf.addChangeListener(new ConfigListener(this));
123 reproducibleRandom = conf.getBoolean("vm.reproducible_random", true);
124 constantSeed = conf.getLong("vm.random_seed", 42);
125 defaultIntSet = conf.getIntArray("vm.random_ints", Integer.MIN_VALUE, 0, Integer.MAX_VALUE);
126 defaultDoubleSet = conf.getDoubleArray("vm.random_doubles", Double.MIN_VALUE, 0, Double.MAX_VALUE);
127 defaultLongSet = conf.getLongArray("vm.random_longs", Long.MIN_VALUE, 0, Long.MAX_VALUE);
128 defaultFloatSet = conf.getFloatArray("vm.random_floats", Float.MIN_VALUE, 0, Float.MAX_VALUE);
131 void setEnumerateRandom (Config conf) {
132 enumerateRandom = conf.getBoolean("cg.enumerate_random", false);
134 if (enumerateRandom){
135 JPF_gov_nasa_jpf_vm_Verify.init(conf);
139 long computeDefaultSeed(){
140 Random rand = (reproducibleRandom) ? new Random(constantSeed) : new Random();
141 return getNativeSeed( rand);
144 static void storeSeed (MJIEnv env, int objRef, long seed){
145 env.setLongField(objRef, "seed", seed);
148 static long getSeed (MJIEnv env, int objRef){
149 return env.getLongField(objRef, "seed");
152 static void restoreRandomState (MJIEnv env, int objRef, Random rand){
153 long seed = getSeed( env, objRef);
154 setNativeSeed( rand, seed);
157 static void storeRandomState (MJIEnv env, int objRef, Random rand){
158 long seed = getNativeSeed( rand);
159 storeSeed( env, objRef, seed);
166 public void $init____V (MJIEnv env, int objRef){
167 long seed = computeDefaultSeed();
168 storeSeed( env, objRef, seed);
172 public void $init__J__V (MJIEnv env, int objRef, long seedStarter){
173 // note - the provided seedStarter is modified by java.util.Random, it is
174 // NOT the internal value that is consecutively used
175 Random rand = new Random(seedStarter);
176 storeRandomState(env, objRef, rand);
180 public void setSeed__J__V (MJIEnv env, int objRef, long seedStarter){
181 // my, what an effort to change a long.
182 restoreRandomState( env, objRef, delegatee);
183 delegatee.setSeed(seedStarter); // compute the new internal value
184 storeRandomState(env, objRef, delegatee);
188 public boolean nextBoolean____Z (MJIEnv env, int objRef){
189 if (enumerateRandom){
190 return JPF_gov_nasa_jpf_vm_Verify.getBoolean____Z(env,-1);
193 restoreRandomState(env, objRef, delegatee);
194 boolean ret = delegatee.nextBoolean();
195 storeRandomState(env, objRef, delegatee);
201 public int nextInt__I__I (MJIEnv env, int objRef, int n){
202 if (enumerateRandom){
203 return JPF_gov_nasa_jpf_vm_Verify.getInt__II__I(env,-1,0,n-1);
206 restoreRandomState(env, objRef, delegatee);
207 int ret = delegatee.nextInt(n);
208 storeRandomState(env, objRef, delegatee);
214 public int nextInt____I (MJIEnv env, int objRef){
215 if (enumerateRandom){
216 return JPF_gov_nasa_jpf_vm_Verify.getIntFromList(env, defaultIntSet);
219 restoreRandomState(env, objRef, delegatee);
220 int ret = delegatee.nextInt();
221 storeRandomState(env, objRef, delegatee);
227 public int next__I__I (MJIEnv env, int objRef, int nBits){
228 if (enumerateRandom){
229 // <2do> we can't do this with an interval since it most likely would explode our state space
230 return JPF_gov_nasa_jpf_vm_Verify.getIntFromList(env, defaultIntSet);
233 restoreRandomState(env, objRef, delegatee);
234 int ret = delegatee.next( nBits);
235 storeRandomState(env, objRef, delegatee);
241 public void nextBytes___3B__V (MJIEnv env, int objRef, int dataRef){
242 // <2do> this one is an even worse state exploder. We could use cascaded CGs,
243 // but chances are this really kills us, so we just ignore 'enumerateRandom' for now
245 int n = env.getArrayLength(dataRef);
246 byte[] data = new byte[n];
248 restoreRandomState(env, objRef, delegatee);
249 delegatee.nextBytes(data);
250 storeRandomState(env, objRef, delegatee);
252 for (int i = 0; i < n; i++) {
253 env.setByteArrayElement(dataRef, i, data[i]);
258 public long nextLong____J (MJIEnv env, int objRef){
259 if (enumerateRandom){
260 return JPF_gov_nasa_jpf_vm_Verify.getLongFromList(env, defaultLongSet);
263 restoreRandomState(env, objRef, delegatee);
264 long ret = delegatee.nextLong();
265 storeRandomState(env, objRef, delegatee);
271 public float nextFloat____F (MJIEnv env, int objRef){
272 if (enumerateRandom){
273 return JPF_gov_nasa_jpf_vm_Verify.getFloatFromList(env, defaultFloatSet);
276 restoreRandomState(env, objRef, delegatee);
277 float ret = delegatee.nextFloat();
278 storeRandomState(env, objRef, delegatee);
284 public double nextDouble____D (MJIEnv env, int objRef){
285 if (enumerateRandom){
286 return JPF_gov_nasa_jpf_vm_Verify.getDoubleFromList(env, defaultDoubleSet);
289 restoreRandomState(env, objRef, delegatee);
290 double ret = delegatee.nextDouble();
291 storeRandomState(env, objRef, delegatee);
297 public double nextGaussian____D (MJIEnv env, int objRef){
298 // <2do> we don't support this yet, neither for enumerateRandom nor
299 // delegation (which would require an additional 'haveNextGaussian' state)
300 restoreRandomState(env, objRef, delegatee);
301 double ret = delegatee.nextGaussian();
302 storeRandomState(env, objRef, delegatee);