Mercurial > hg > Members > kono > jpf-core
view src/main/gov/nasa/jpf/vm/JenkinsStateSet.java @ 34:49be04cc6389 default tip java9-try
cyclic dependency ...
author | Shinji KONO <kono@ie.u-ryukyu.ac.jp> |
---|---|
date | Tue, 19 Dec 2017 11:21:23 +0900 |
parents | 61d41facf527 |
children |
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; // // Contributed by Peter C. Dillinger and the Georgia Tech Research Corporation // // Portions drawn from public domain work by Bob Jenkins, May 2006 // // Modified by Peter C. Dillinger working under Mission Critical Technologies // //import gov.nasa.jpf.util.LongVector; /** * Implements StateSet based on Jenkins hashes. */ public class JenkinsStateSet extends SerializingStateSet { static final double MAX_LOAD = 0.7; static final int INIT_SIZE = 65536; int lastStateId = -1; //LongVector fingerprints; long[] fingerprints; int[] hashtable; int nextRehash; public JenkinsStateSet() { lastStateId = -1; hashtable = new int[INIT_SIZE]; nextRehash = (int) (MAX_LOAD * INIT_SIZE); //fingerprints = new LongVector(nextRehash / 2); fingerprints = new long[nextRehash/2]; } @Override public int size () { return lastStateId + 1; } public static long longLookup3Hash(int[] val) { // Jenkins' LOOKUP3 hash (May 2006) int a = 0x510fb60d; int b = 0xa4cb30d9 + (val.length); int c = 0x9e3779b9; int i; int max = val.length - 2; for (i = 0; i < max; i += 3) { a += val[i]; b += val[i + 1]; c += val[i + 2]; a -= c; a ^= (c << 4) ^ (c >>> 28); c += b; b -= a; b ^= (a << 6) ^ (a >>> 26); a += c; c -= b; c ^= (b << 8) ^ (b >>> 24); b += a; a -= c; a ^= (c << 16)^ (c >>> 16); c += b; b -= a; b ^= (a << 19)^ (a >>> 13); a += c; c -= b; c ^= (b << 4) ^ (b >>> 28); b += a; } switch (val.length - i) { case 2: c += val[val.length - 2]; b += val[val.length - 1]; break; case 1: b += val[val.length - 1]; break; } c ^= b; c -= (b << 14) ^ (b >>> 18); a ^= c; a -= (c << 11) ^ (c >>> 21); b ^= a; b -= (a << 25) ^ (a >>> 7); c ^= b; c -= (b << 16) ^ (b >>> 16); a ^= c; a -= (c << 4) ^ (c >>> 28); b ^= a; b -= (a << 14) ^ (a >>> 18); c ^= b; c -= (b << 24) ^ (b >>> 8); return ((long)c << 32) ^ b ^ a; } @Override public int add (int[] val) { long hash = longLookup3Hash(val); // this is the expensive part int i; // hash table lookup & add; open-addressed, double hashing int mask = hashtable.length - 1; int idx = (int)(hash >> 32) & mask; int delta = (int)hash | 1; // must be odd! int oidx = idx; while (hashtable[idx] != 0) { int id = hashtable[idx] - 1; // in table, 1 higher //if (fingerprints.get(id) == hash) { if (fingerprints[id] == hash){ return id; } idx = (idx + delta) & mask; assert (idx != oidx); // should never wrap around } assert (hashtable[idx] == 0); // should never fill up if (lastStateId >= nextRehash) { // too full hashtable = null; // run GC here? hashtable = new int[(mask + 1) << 1]; mask = hashtable.length - 1; nextRehash = (int) (MAX_LOAD * mask); for (i = 0; i <= lastStateId; i++) { //long h = fingerprints.get(i); long h = fingerprints[i]; idx = (int)(h >> 32) & mask; delta = (int)h | 1; while (hashtable[idx] != 0) { // we know enough slots exist idx = (idx + delta) & mask; } hashtable[idx] = i + 1; // in table, add 1 } // done with rehash; now get idx to empty slot idx = (int)(hash >> 32) & mask; delta = (int)hash | 1; // must be odd! while (hashtable[idx] != 0) { // we know enough slots exist and state is // new idx = (idx + delta) & mask; } } else { // idx already pointing to empty slot } //--- only reached if state is new lastStateId++; hashtable[idx] = lastStateId + 1; // in table, add 1 //fingerprints.set(lastStateId, hash); try { // this happens rarely enough to save on nominal branch instructions fingerprints[lastStateId] = hash; } catch (ArrayIndexOutOfBoundsException ix){ growFingerprint(lastStateId); fingerprints[lastStateId] = hash; } return lastStateId; } void growFingerprint (int minSize){ // we don't try to be fancy here int newSize = fingerprints.length *2; if (newSize < minSize) { newSize = minSize; } long[] newFingerprints = new long[newSize]; System.arraycopy( fingerprints, 0, newFingerprints, 0, fingerprints.length); fingerprints = newFingerprints; } /** * Main for testing speed, mostly. */ public static void main(String[] args) { try { int vlen = Integer.parseInt(args[0]); int adds = Integer.parseInt(args[1]); int queries = Integer.parseInt(args[2]); if (queries > adds) { queries = adds; System.err.println("Truncating queries to " + queries); } int[] v = new int[vlen]; int i; for (i = 0; i < vlen; i++) { v[i] = i - 42; } JenkinsStateSet set = new JenkinsStateSet(); long t1 = System.currentTimeMillis(); for (i = 0; i < adds; i++) { v[0] = i * 3; set.add(v); assert set.size() == i+1; } for (i = 0; i < queries; i++) { v[0] = i * 3; set.add(v); assert set.size() == adds; } long t2 = System.currentTimeMillis(); System.out.println("duration: " + (t2 - t1)); } catch (RuntimeException re) { re.printStackTrace(); System.err.println("args: vector_length #adds #queries"); } } }