comparison src/main/gov/nasa/jpf/vm/ClassInfo.java @ 23:db918c531e6d

streamlined class init, which was a mixed case of registerClass()/initializeClass() and pushRequiredClinits(). Now it is a single initializeClass(ti) method which combines the previous initializeClass(), pushRequiredClinits() and pushClinit() methods. The reason for combining these is the forthcoming replacement of separately locked clinits from different DirectCallStackFrames with a single synthetic frame that calls clinits from nested synchronized blocks. This is required to model hotspot, which does cause deadlocks with concurrent init of classes that cause subclass init during their clinit executions.
author Peter Mehlitz <Peter.C.Mehlitz@nasa.gov>
date Wed, 15 Apr 2015 22:40:21 -0700
parents e15b03204dc7
children 6774e2e08d37
comparison
equal deleted inserted replaced
22:cd7880ab73c7 23:db918c531e6d
1963 1963
1964 public static ClassInfo getInitializedSystemClassInfo (String clsName, ThreadInfo ti){ 1964 public static ClassInfo getInitializedSystemClassInfo (String clsName, ThreadInfo ti){
1965 ClassLoaderInfo systemLoader = ClassLoaderInfo.getCurrentSystemClassLoader(); 1965 ClassLoaderInfo systemLoader = ClassLoaderInfo.getCurrentSystemClassLoader();
1966 ClassInfo ci = systemLoader.getResolvedClassInfo(clsName); 1966 ClassInfo ci = systemLoader.getResolvedClassInfo(clsName);
1967 1967
1968 ci.registerClass(ti); // this is safe to call on already loaded classes
1969
1970 if (ci.initializeClass(ti)) { 1968 if (ci.initializeClass(ti)) {
1971 throw new ClinitRequired(ci); 1969 throw new ClinitRequired(ci);
1972 } 1970 }
1973 1971
1974 return ci; 1972 return ci;
2142 StaticElementInfo sei = getModifiableStaticElementInfo(); 2140 StaticElementInfo sei = getModifiableStaticElementInfo();
2143 sei.setStatus(ti.getId()); 2141 sei.setStatus(ti.getId());
2144 } 2142 }
2145 2143
2146 /** 2144 /**
2147 * check if this class requires clinit execution. If so, 2145 * initialize this class and its superclasses (but not interfaces)
2148 * push the corresponding DirectCallStackFrames. 2146 * this will cause execution of clinits of not-yet-initialized classes in this hierarchy
2149 *
2150 * clients have to be aware of that frames might get pushed
2151 * and properly handle re-execution
2152 */
2153 public boolean pushRequiredClinits (ThreadInfo ti){
2154 StaticElementInfo sei = getStaticElementInfo();
2155 if (sei == null) {
2156 sei = registerClass(ti);
2157 }
2158
2159 return initializeClass(ti); // indicates if we pushed clinits
2160 }
2161
2162 public void setInitialized() {
2163 StaticElementInfo sei = getModifiableStaticElementInfo();
2164 sei.setStatus(INITIALIZED);
2165
2166 // we don't emit classLoaded() notifications for non-builtin classes
2167 // here anymore because it would be confusing to get instructionExecuted()
2168 // notifications from the <clinit> execution before the classLoaded()
2169 }
2170
2171 /**
2172 * perform static initialization of class
2173 * this recursively initializes all super classes, but NOT the interfaces
2174 * 2147 *
2175 * @param ti executing thread 2148 * note - we don't treat registration/initialization of a class as
2176 * @return true if clinit stackframes were pushed, idx.e. context instruction 2149 * a sharedness-changing operation since it is done automatically by
2177 * needs to be re-executed 2150 * the VM and the triggering action in the SUT (e.g. static field access or method call)
2178 */ 2151 * is the one that should update sharedness and/or break the transition accordingly
2179 public boolean initializeClass (ThreadInfo ti) { 2152 *
2153 * @return true - if initialization pushed DirectCallStackFrames and caller has to re-execute
2154 */
2155 public boolean initializeClass(ThreadInfo ti){
2180 int pushedFrames = 0; 2156 int pushedFrames = 0;
2181 2157
2182 // push clinits of class hierarchy (upwards, since call stack is LIFO) 2158 // push clinits of class hierarchy (upwards, since call stack is LIFO)
2183 for (ClassInfo ci = this; ci != null; ci = ci.getSuperClass()) { 2159 for (ClassInfo ci = this; ci != null; ci = ci.getSuperClass()) {
2184 if (ci.pushClinit(ti)) { 2160 StaticElementInfo sei = ci.getStaticElementInfo();
2185 2161 if (sei == null){
2186 // note - we don't treat registration/initialization of a class as 2162 sei = ci.registerClass(ti);
2187 // a sharedness-changing operation since it is done automatically by 2163 }
2188 // the VM and the triggering action in the SUT (e.g. static field access or method call) 2164
2189 // is the one that should update sharedness and/or break the transition accordingly 2165 int status = sei.getStatus();
2190 2166 if (status != INITIALIZED){
2191 // we can't do setInitializing() yet because there is no global lock that 2167 // we can't do setInitializing() yet because there is no global lock that
2192 // covers the whole clinit chain, and we might have a context switch before executing 2168 // covers the whole clinit chain, and we might have a context switch before executing
2193 // a already pushed subclass clinit - there can be races as to which thread 2169 // a already pushed subclass clinit - there can be races as to which thread
2194 // does the static init first. Note this case is checked in INVOKECLINIT 2170 // does the static init first. Note this case is checked in INVOKECLINIT
2195 // (which is one of the reasons why we have it). 2171 // (which is one of the reasons why we have it).
2196 pushedFrames++; 2172
2197 } 2173 if (status != ti.getId()) {
2198 } 2174 // even if it is already initializing - if it does not happen in the current thread
2199 2175 // we have to sync, which we do by calling clinit
2200 return (pushedFrames > 0); 2176 MethodInfo mi = ci.getMethod("<clinit>()V", false);
2201 } 2177 if (mi != null) {
2202 2178 DirectCallStackFrame frame = ci.createDirectCallStackFrame(ti, mi, 0);
2203 /** 2179 ti.pushFrame( frame);
2204 * local class initialization 2180 pushedFrames++;
2205 * @return true if we pushed a &lt;clinit&gt; frame 2181
2206 */ 2182 } else {
2207 protected boolean pushClinit (ThreadInfo ti) { 2183 // it has no clinit, we can set it initialized
2208 StaticElementInfo sei = getStaticElementInfo(); 2184 ci.setInitialized();
2209 int stat = sei.getStatus(); 2185 }
2210
2211 if (stat != INITIALIZED) {
2212 if (stat != ti.getId()) {
2213 // even if it is already initializing - if it does not happen in the current thread
2214 // we have to sync, which we do by calling clinit
2215 MethodInfo mi = getMethod("<clinit>()V", false);
2216 if (mi != null) {
2217 DirectCallStackFrame frame = createDirectCallStackFrame(ti, mi, 0);
2218 ti.pushFrame( frame);
2219 return true;
2220
2221 } else { 2186 } else {
2222 // it has no clinit, so it already is initialized 2187 // ignore if it's already being initialized by our own thread (recursive request)
2223 setInitialized();
2224 } 2188 }
2225 } else { 2189 } else {
2226 // ignore if it's already being initialized by our own thread (recursive request) 2190 break; // if this class is initialized, so are its superclasses
2227 } 2191 }
2228 } 2192 }
2229 2193
2230 return false; 2194 return (pushedFrames > 0);
2195 }
2196
2197 public void setInitialized() {
2198 StaticElementInfo sei = getModifiableStaticElementInfo();
2199 sei.setStatus(INITIALIZED);
2200
2201 // we don't emit classLoaded() notifications for non-builtin classes
2202 // here anymore because it would be confusing to get instructionExecuted()
2203 // notifications from the <clinit> execution before the classLoaded()
2231 } 2204 }
2232 2205
2233 public StaticElementInfo getStaticElementInfo() { 2206 public StaticElementInfo getStaticElementInfo() {
2234 if (id != -1) { 2207 if (id != -1) {
2235 return classLoader.getStatics().get( id); 2208 return classLoader.getStatics().get( id);