Mercurial > hg > Members > kono > jpf-core
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 <clinit> 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); |