# HG changeset patch # User Peter Mehlitz # Date 1429162821 25200 # Node ID db918c531e6df8a1a11ee7f6b5857913e98aa278 # Parent cd7880ab73c7ff557161756eb75e607a77ccc352 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. diff -r cd7880ab73c7 -r db918c531e6d .idea/compiler.xml --- a/.idea/compiler.xml Tue Apr 14 15:01:25 2015 -0700 +++ b/.idea/compiler.xml Wed Apr 15 22:40:21 2015 -0700 @@ -18,5 +18,6 @@ + \ No newline at end of file diff -r cd7880ab73c7 -r db918c531e6d .idea/misc.xml --- a/.idea/misc.xml Tue Apr 14 15:01:25 2015 -0700 +++ b/.idea/misc.xml Wed Apr 15 22:40:21 2015 -0700 @@ -51,7 +51,7 @@ - + \ No newline at end of file diff -r cd7880ab73c7 -r db918c531e6d src/main/gov/nasa/jpf/jvm/bytecode/GETSTATIC.java --- a/src/main/gov/nasa/jpf/jvm/bytecode/GETSTATIC.java Tue Apr 14 15:01:25 2015 -0700 +++ b/src/main/gov/nasa/jpf/jvm/bytecode/GETSTATIC.java Wed Apr 15 22:40:21 2015 -0700 @@ -56,7 +56,7 @@ //--- check if this has to trigger class initialization ClassInfo ciField = fieldInfo.getClassInfo(); - if (!mi.isClinit(ciField) && ciField.pushRequiredClinits(ti)) { + if (!mi.isClinit(ciField) && ciField.initializeClass(ti)) { // note - this returns the next insn in the topmost clinit that just got pushed return ti.getPC(); } diff -r cd7880ab73c7 -r db918c531e6d src/main/gov/nasa/jpf/jvm/bytecode/INVOKEDYNAMIC.java --- a/src/main/gov/nasa/jpf/jvm/bytecode/INVOKEDYNAMIC.java Tue Apr 14 15:01:25 2015 -0700 +++ b/src/main/gov/nasa/jpf/jvm/bytecode/INVOKEDYNAMIC.java Wed Apr 15 22:40:21 2015 -0700 @@ -105,10 +105,6 @@ return ti.getPC(); } - if (!fiClassInfo.isRegistered()){ - fiClassInfo.registerClass(ti); - } - if (fiClassInfo.initializeClass(ti)) { return ti.getPC(); } diff -r cd7880ab73c7 -r db918c531e6d src/main/gov/nasa/jpf/jvm/bytecode/INVOKESTATIC.java --- a/src/main/gov/nasa/jpf/jvm/bytecode/INVOKESTATIC.java Tue Apr 14 15:01:25 2015 -0700 +++ b/src/main/gov/nasa/jpf/jvm/bytecode/INVOKESTATIC.java Wed Apr 15 22:40:21 2015 -0700 @@ -92,7 +92,7 @@ // this can be actually different than (can be a base) ClassInfo ciCallee = callee.getClassInfo(); - if (ciCallee.pushRequiredClinits(ti)) { + if (ciCallee.initializeClass(ti)) { // do class initialization before continuing // note - this returns the next insn in the topmost clinit that just got pushed return ti.getPC(); diff -r cd7880ab73c7 -r db918c531e6d src/main/gov/nasa/jpf/jvm/bytecode/NEW.java --- a/src/main/gov/nasa/jpf/jvm/bytecode/NEW.java Tue Apr 14 15:01:25 2015 -0700 +++ b/src/main/gov/nasa/jpf/jvm/bytecode/NEW.java Wed Apr 15 22:40:21 2015 -0700 @@ -57,16 +57,11 @@ return ti.getPC(); } - if (!ci.isRegistered()){ - ci.registerClass(ti); + if (ci.initializeClass(ti)){ + // continue with the topframe and re-exec this insn once the clinits are done + return ti.getPC(); } - // we might have to execute clinits - if (ci.initializeClass(ti)) { - // continue with the topframe and re-exec this insn once the clinits are done - return ti.getPC(); - } - if (heap.isOutOfMemory()) { // simulate OutOfMemoryError return ti.createAndThrowException("java.lang.OutOfMemoryError", "trying to allocate new " + cname); diff -r cd7880ab73c7 -r db918c531e6d src/main/gov/nasa/jpf/jvm/bytecode/PUTSTATIC.java --- a/src/main/gov/nasa/jpf/jvm/bytecode/PUTSTATIC.java Tue Apr 14 15:01:25 2015 -0700 +++ b/src/main/gov/nasa/jpf/jvm/bytecode/PUTSTATIC.java Wed Apr 15 22:40:21 2015 -0700 @@ -67,7 +67,7 @@ //--- check if this has to trigger class initialization ClassInfo ciField = fieldInfo.getClassInfo(); - if (!mi.isClinit(ciField) && ciField.pushRequiredClinits(ti)) { + if (!mi.isClinit(ciField) && ciField.initializeClass(ti)) { return ti.getPC(); // this returns the next insn in the topmost clinit that just got pushed } ElementInfo eiFieldOwner = ciField.getModifiableStaticElementInfo(); diff -r cd7880ab73c7 -r db918c531e6d src/main/gov/nasa/jpf/util/json/JSONObject.java --- a/src/main/gov/nasa/jpf/util/json/JSONObject.java Tue Apr 14 15:01:25 2015 -0700 +++ b/src/main/gov/nasa/jpf/util/json/JSONObject.java Wed Apr 15 22:40:21 2015 -0700 @@ -99,7 +99,7 @@ */ public boolean requiresClinitExecution (ClassInfo ci, ThreadInfo ti){ while (ci != null){ - if (ci.pushRequiredClinits(ti)){ + if (ci.initializeClass(ti)){ return true; } @@ -183,7 +183,7 @@ } else { // Not a special case. Fill it recursively ClassInfo ciField = fi.getTypeClassInfo(); - if (ciField.pushRequiredClinits(env.getThreadInfo())){ + if (ciField.initializeClass(env.getThreadInfo())){ throw new ClinitRequired(ciField); } diff -r cd7880ab73c7 -r db918c531e6d src/main/gov/nasa/jpf/vm/ClassInfo.java --- a/src/main/gov/nasa/jpf/vm/ClassInfo.java Tue Apr 14 15:01:25 2015 -0700 +++ b/src/main/gov/nasa/jpf/vm/ClassInfo.java Wed Apr 15 22:40:21 2015 -0700 @@ -1965,8 +1965,6 @@ ClassLoaderInfo systemLoader = ClassLoaderInfo.getCurrentSystemClassLoader(); ClassInfo ci = systemLoader.getResolvedClassInfo(clsName); - ci.registerClass(ti); // this is safe to call on already loaded classes - if (ci.initializeClass(ti)) { throw new ClinitRequired(ci); } @@ -2144,19 +2142,56 @@ } /** - * check if this class requires clinit execution. If so, - * push the corresponding DirectCallStackFrames. - * - * clients have to be aware of that frames might get pushed - * and properly handle re-execution + * initialize this class and its superclasses (but not interfaces) + * this will cause execution of clinits of not-yet-initialized classes in this hierarchy + * + * note - we don't treat registration/initialization of a class as + * a sharedness-changing operation since it is done automatically by + * the VM and the triggering action in the SUT (e.g. static field access or method call) + * is the one that should update sharedness and/or break the transition accordingly + * + * @return true - if initialization pushed DirectCallStackFrames and caller has to re-execute */ - public boolean pushRequiredClinits (ThreadInfo ti){ - StaticElementInfo sei = getStaticElementInfo(); - if (sei == null) { - sei = registerClass(ti); + public boolean initializeClass(ThreadInfo ti){ + int pushedFrames = 0; + + // push clinits of class hierarchy (upwards, since call stack is LIFO) + for (ClassInfo ci = this; ci != null; ci = ci.getSuperClass()) { + StaticElementInfo sei = ci.getStaticElementInfo(); + if (sei == null){ + sei = ci.registerClass(ti); + } + + int status = sei.getStatus(); + if (status != INITIALIZED){ + // we can't do setInitializing() yet because there is no global lock that + // covers the whole clinit chain, and we might have a context switch before executing + // a already pushed subclass clinit - there can be races as to which thread + // does the static init first. Note this case is checked in INVOKECLINIT + // (which is one of the reasons why we have it). + + if (status != ti.getId()) { + // even if it is already initializing - if it does not happen in the current thread + // we have to sync, which we do by calling clinit + MethodInfo mi = ci.getMethod("()V", false); + if (mi != null) { + DirectCallStackFrame frame = ci.createDirectCallStackFrame(ti, mi, 0); + ti.pushFrame( frame); + pushedFrames++; + + } else { + // it has no clinit, we can set it initialized + ci.setInitialized(); + } + } else { + // ignore if it's already being initialized by our own thread (recursive request) + } + } else { + break; // if this class is initialized, so are its superclasses + } } - return initializeClass(ti); // indicates if we pushed clinits + return (pushedFrames > 0); } public void setInitialized() { @@ -2168,68 +2203,6 @@ // notifications from the execution before the classLoaded() } - /** - * perform static initialization of class - * this recursively initializes all super classes, but NOT the interfaces - * - * @param ti executing thread - * @return true if clinit stackframes were pushed, idx.e. context instruction - * needs to be re-executed - */ - public boolean initializeClass (ThreadInfo ti) { - int pushedFrames = 0; - - // push clinits of class hierarchy (upwards, since call stack is LIFO) - for (ClassInfo ci = this; ci != null; ci = ci.getSuperClass()) { - if (ci.pushClinit(ti)) { - - // note - we don't treat registration/initialization of a class as - // a sharedness-changing operation since it is done automatically by - // the VM and the triggering action in the SUT (e.g. static field access or method call) - // is the one that should update sharedness and/or break the transition accordingly - - // we can't do setInitializing() yet because there is no global lock that - // covers the whole clinit chain, and we might have a context switch before executing - // a already pushed subclass clinit - there can be races as to which thread - // does the static init first. Note this case is checked in INVOKECLINIT - // (which is one of the reasons why we have it). - pushedFrames++; - } - } - - return (pushedFrames > 0); - } - - /** - * local class initialization - * @return true if we pushed a <clinit> frame - */ - protected boolean pushClinit (ThreadInfo ti) { - StaticElementInfo sei = getStaticElementInfo(); - int stat = sei.getStatus(); - - if (stat != INITIALIZED) { - if (stat != ti.getId()) { - // even if it is already initializing - if it does not happen in the current thread - // we have to sync, which we do by calling clinit - MethodInfo mi = getMethod("()V", false); - if (mi != null) { - DirectCallStackFrame frame = createDirectCallStackFrame(ti, mi, 0); - ti.pushFrame( frame); - return true; - - } else { - // it has no clinit, so it already is initialized - setInitialized(); - } - } else { - // ignore if it's already being initialized by our own thread (recursive request) - } - } - - return false; - } - public StaticElementInfo getStaticElementInfo() { if (id != -1) { return classLoader.getStatics().get( id); diff -r cd7880ab73c7 -r db918c531e6d src/main/gov/nasa/jpf/vm/ClassLoaderInfo.java --- a/src/main/gov/nasa/jpf/vm/ClassLoaderInfo.java Tue Apr 14 15:01:25 2015 -0700 +++ b/src/main/gov/nasa/jpf/vm/ClassLoaderInfo.java Wed Apr 15 22:40:21 2015 -0700 @@ -481,8 +481,6 @@ public ClassInfo getInitializedClassInfo (String clsName, ThreadInfo ti){ ClassInfo ci = getResolvedClassInfo(clsName); - ci.registerClass(ti); // this is safe to call on already loaded classes - if (ci.initializeClass(ti)) { throw new ClinitRequired(ci); } diff -r cd7880ab73c7 -r db918c531e6d src/main/gov/nasa/jpf/vm/Instruction.java --- a/src/main/gov/nasa/jpf/vm/Instruction.java Tue Apr 14 15:01:25 2015 -0700 +++ b/src/main/gov/nasa/jpf/vm/Instruction.java Wed Apr 15 22:40:21 2015 -0700 @@ -335,7 +335,7 @@ * used in a number of external projects */ public boolean requiresClinitExecution(ThreadInfo ti, ClassInfo ci) { - return ci.pushRequiredClinits(ti); + return ci.initializeClass(ti); } /** diff -r cd7880ab73c7 -r db918c531e6d src/main/gov/nasa/jpf/vm/MJIEnv.java --- a/src/main/gov/nasa/jpf/vm/MJIEnv.java Tue Apr 14 15:01:25 2015 -0700 +++ b/src/main/gov/nasa/jpf/vm/MJIEnv.java Wed Apr 15 22:40:21 2015 -0700 @@ -1038,7 +1038,7 @@ } public ElementInfo newElementInfo (ClassInfo ci){ - if (ci.pushRequiredClinits(ti)){ + if (ci.initializeClass(ti)){ throw new ClinitRequired(ci); } @@ -1291,7 +1291,7 @@ * Do a repeatInvocation() in this case */ public boolean requiresClinitExecution(ClassInfo ci) { - return ci.pushRequiredClinits(ti); + return ci.initializeClass(ti); } /** @@ -1744,7 +1744,7 @@ // NOTE: we have to repeat no matter what, since this is called from // a handler context (if we only had to create a class object w/o // calling clinit, we can't just go on) - ci.pushRequiredClinits(ti); + ci.initializeClass(ti); repeatInvocation(); } diff -r cd7880ab73c7 -r db918c531e6d src/main/gov/nasa/jpf/vm/ThreadInfo.java --- a/src/main/gov/nasa/jpf/vm/ThreadInfo.java Tue Apr 14 15:01:25 2015 -0700 +++ b/src/main/gov/nasa/jpf/vm/ThreadInfo.java Wed Apr 15 22:40:21 2015 -0700 @@ -31,7 +31,6 @@ import gov.nasa.jpf.util.Predicate; import gov.nasa.jpf.util.StringSetMatcher; import gov.nasa.jpf.vm.choice.BreakGenerator; -import gov.nasa.jpf.vm.choice.ThreadChoiceFromSet; import java.io.PrintWriter; import java.io.File; @@ -1776,10 +1775,6 @@ * thrown by the VM (or a listener) */ public Instruction createAndThrowException (ClassInfo ci, String details) { - if (!ci.isRegistered()) { - ci.registerClass(this); - } - if (ci.initializeClass(this)) { return getPC(); } diff -r cd7880ab73c7 -r db918c531e6d src/peers/gov/nasa/jpf/vm/JPF_gov_nasa_jpf_SerializationConstructor.java --- a/src/peers/gov/nasa/jpf/vm/JPF_gov_nasa_jpf_SerializationConstructor.java Tue Apr 14 15:01:25 2015 -0700 +++ b/src/peers/gov/nasa/jpf/vm/JPF_gov_nasa_jpf_SerializationConstructor.java Wed Apr 15 22:40:21 2015 -0700 @@ -19,12 +19,6 @@ package gov.nasa.jpf.vm; import gov.nasa.jpf.annotation.MJI; -import gov.nasa.jpf.vm.ClassInfo; -import gov.nasa.jpf.vm.DirectCallStackFrame; -import gov.nasa.jpf.vm.MJIEnv; -import gov.nasa.jpf.vm.MethodInfo; -import gov.nasa.jpf.vm.NativePeer; -import gov.nasa.jpf.vm.ThreadInfo; public class JPF_gov_nasa_jpf_SerializationConstructor extends NativePeer { @@ -57,7 +51,7 @@ ti.pushFrame(frame); // check for & push required clinits - ci.pushRequiredClinits(ti); + ci.initializeClass(ti); env.repeatInvocation(); return MJIEnv.NULL; diff -r cd7880ab73c7 -r db918c531e6d src/peers/gov/nasa/jpf/vm/JPF_java_io_RandomAccessFile.java --- a/src/peers/gov/nasa/jpf/vm/JPF_java_io_RandomAccessFile.java Tue Apr 14 15:01:25 2015 -0700 +++ b/src/peers/gov/nasa/jpf/vm/JPF_java_io_RandomAccessFile.java Wed Apr 15 22:40:21 2015 -0700 @@ -63,7 +63,7 @@ Instruction insn = ti.getPC(); ClassInfo ci = ClassLoaderInfo.getSystemResolvedClassInfo(DataRepresentation); - if (ci.pushRequiredClinits(ti)){ + if (ci.initializeClass(ti)){ env.repeatInvocation(); return null; } diff -r cd7880ab73c7 -r db918c531e6d src/peers/gov/nasa/jpf/vm/JPF_java_lang_Class.java --- a/src/peers/gov/nasa/jpf/vm/JPF_java_lang_Class.java Tue Apr 14 15:01:25 2015 -0700 +++ b/src/peers/gov/nasa/jpf/vm/JPF_java_lang_Class.java Wed Apr 15 22:40:21 2015 -0700 @@ -57,7 +57,7 @@ Instruction insn = ti.getPC(); ClassInfo ci = env.getReferredClassInfo( robj).getComponentClassInfo(); - if (ci.pushRequiredClinits(ti)){ + if (ci.initializeClass(ti)){ env.repeatInvocation(); return MJIEnv.NULL; } @@ -156,7 +156,7 @@ ThreadInfo ti = env.getThreadInfo(); Instruction insn = ti.getPC(); - if (ci.pushRequiredClinits(ti)){ + if (ci.initializeClass(ti)){ env.repeatInvocation(); return MJIEnv.NULL; } @@ -247,7 +247,7 @@ ti.pushFrame(frame); // check if we have to push clinits - ci.pushRequiredClinits(ti); + ci.initializeClass(ti); env.repeatInvocation(); return MJIEnv.NULL; @@ -495,7 +495,7 @@ Instruction insn = ti.getPC(); ClassInfo ci = ClassLoaderInfo.getSystemResolvedClassInfo( clsName); - if (ci.pushRequiredClinits(ti)){ + if (ci.initializeClass(ti)){ return null; } else { return ci; @@ -505,7 +505,7 @@ @MJI public void initialize0____V (MJIEnv env, int clsObjRef){ ClassInfo ci = env.getReferredClassInfo( clsObjRef); - ci.pushRequiredClinits(ThreadInfo.currentThread); + ci.initializeClass(ThreadInfo.currentThread); } Set getInitializedInterfaces (MJIEnv env, ClassInfo ci){ @@ -514,7 +514,7 @@ Set ifcs = ci.getAllInterfaceClassInfos(); for (ClassInfo ciIfc : ifcs){ - if (ciIfc.pushRequiredClinits(ti)){ + if (ciIfc.initializeClass(ti)){ return null; } } @@ -742,17 +742,12 @@ if (ciEncl == null){ return MJIEnv.NULL; } - - if (!ciEncl.isRegistered()){ - ThreadInfo ti = env.getThreadInfo(); - ciEncl.registerClass(ti); - - if (ciEncl.initializeClass(ti)){ - env.repeatInvocation(); - return 0; - } + + if (ciEncl.initializeClass(env.getThreadInfo())) { + env.repeatInvocation(); + return 0; } - + return ciEncl.getClassObjectRef(); } diff -r cd7880ab73c7 -r db918c531e6d src/peers/gov/nasa/jpf/vm/JPF_java_lang_System.java --- a/src/peers/gov/nasa/jpf/vm/JPF_java_lang_System.java Tue Apr 14 15:01:25 2015 -0700 +++ b/src/peers/gov/nasa/jpf/vm/JPF_java_lang_System.java Wed Apr 15 22:40:21 2015 -0700 @@ -71,12 +71,6 @@ StackFrame frame = ti.getTopFrame(); ClassInfo ci = ClassLoaderInfo.getSystemResolvedClassInfo("gov.nasa.jpf.ConsoleOutputStream"); - // it's not really used, but it would be hack'ish to use a class whose - // super class hasn't been initialized yet - if (!ci.isRegistered()) { - ci.registerClass(ti); - } - if (ci.initializeClass(ti)) { env.repeatInvocation(); return MJIEnv.NULL; diff -r cd7880ab73c7 -r db918c531e6d src/peers/gov/nasa/jpf/vm/JPF_java_lang_reflect_Constructor.java --- a/src/peers/gov/nasa/jpf/vm/JPF_java_lang_reflect_Constructor.java Tue Apr 14 15:01:25 2015 -0700 +++ b/src/peers/gov/nasa/jpf/vm/JPF_java_lang_reflect_Constructor.java Wed Apr 15 22:40:21 2015 -0700 @@ -111,7 +111,7 @@ } ti.pushFrame(frame); - ci.pushRequiredClinits(ti); + ci.initializeClass(ti); env.repeatInvocation(); return MJIEnv.NULL; diff -r cd7880ab73c7 -r db918c531e6d src/peers/gov/nasa/jpf/vm/JPF_java_lang_reflect_Field.java --- a/src/peers/gov/nasa/jpf/vm/JPF_java_lang_reflect_Field.java Tue Apr 14 15:01:25 2015 -0700 +++ b/src/peers/gov/nasa/jpf/vm/JPF_java_lang_reflect_Field.java Wed Apr 15 22:40:21 2015 -0700 @@ -630,7 +630,7 @@ static boolean isAvailable (MJIEnv env, FieldInfo fi, int ownerRef){ if (fi.isStatic()){ ClassInfo fci = fi.getClassInfo(); - if (fci.pushRequiredClinits(env.getThreadInfo())){ + if (fci.initializeClass(env.getThreadInfo())){ env.repeatInvocation(); return false; } diff -r cd7880ab73c7 -r db918c531e6d src/peers/gov/nasa/jpf/vm/JPF_java_lang_reflect_Method.java --- a/src/peers/gov/nasa/jpf/vm/JPF_java_lang_reflect_Method.java Tue Apr 14 15:01:25 2015 -0700 +++ b/src/peers/gov/nasa/jpf/vm/JPF_java_lang_reflect_Method.java Wed Apr 15 22:40:21 2015 -0700 @@ -476,7 +476,7 @@ //--- check for and push required clinits if (miCallee.isStatic()){ - calleeClass.pushRequiredClinits(ti); + calleeClass.initializeClass(ti); } return MJIEnv.NULL; // reexecute