public ElementInfo getBlockedObject(ThreadInfo th, boolean isBeforeCall) { int objref; ElementInfo ei = null; if (isSynchronized()) { if (isStatic()) { objref = ci.getClassObjectRef(); } else { // NOTE 'inMethod' doesn't work for natives, because th.getThis() // pulls 'this' from the stack frame, which we don't have (and don't need) // for natives objref = isBeforeCall ? th.getCalleeThis(this) : th.getThis(); } ei = th.getElementInfo(objref); assert (ei != null) : ("inconsistent stack, no object or class ref: " + getCompleteName() + " (" + objref + ")"); } return ei; }
private void enter(ThreadInfo ti) { if (isSynchronized()) { ElementInfo ei = getBlockedObject(ti, true); ei.lock(ti); if (isStatic() && isClinit()) { ci.setInitializing(ti); } } StackFrame frame = new StackFrame(this, ti.getTopFrame()); ti.pushFrame(frame); ti.getVM().notifyMethodEntered(ti, this); }
/** execute this method, which might be either bytecode or native. */ public Instruction execute(ThreadInfo ti) { if (((attrs & MJI_NATIVE) != 0) || isNative()) { NativePeer nativePeer = ci.getNativePeer(); if (nativePeer != null) { JVM vm = ti.getVM(); StackFrame frame = new StackFrame(this, ti.getTopFrame()); // since there is no enter/leave for native methods, we have to do // the notifications explicitly ti.pushFrame(frame); // Make the logic easier in listeners (e.g. vm.getLastMethod() == // vm.getCurrentThread().getMethod()) vm.notifyMethodEntered(ti, this); ti.popFrame( false); // Can't keep the frame for later in this method since nativePeer.executeMethod // will do work on the top of the stack // <2do> Allow for the frame to remain on the stack for the duration of the call to // nativePeer.executeMethod(). Instruction nextInsn = nativePeer.executeMethod(ti, this); ti.pushFrame(frame); // Make the logic easier in listeners (e.g. vm.getLastMethod() == // vm.getCurrentThread().getMethod()) vm.notifyMethodExited(ti, this); ti.popFrame(false); // Can't keep the frame since we don't want to leak frames. return nextInsn; } else { return ti.createAndThrowException( "java.lang.UnsatisfiedLinkError", ci.getName() + '.' + getUniqueName() + " (no peer)"); } } else { enter(ti); return ti.getPC(); } }
public void leave(ThreadInfo ti) { // <2do> - that's not really enough, we might have suspicious bytecode that fails // to release locks acquired by monitor_enter (e.g. by not having a handler that // monitor_exits & re-throws). That's probably shifted into the bytecode verifier // in the future (i.e. outside JPF), but maybe we should add an explicit test here // and report an error if the code does asymmetric locking (according to the specs, // VMs are allowed to silently fix this, so it might run on some and fail on others) if (isSynchronized()) { ElementInfo ei = getBlockedObject(ti, false); ei.unlock(ti); if (isStatic() && isClinit()) { // we just released the lock on the class object, returning from a clinit // now we can consider this class to be initialized. // NOTE this is still part of the RETURN insn of clinit, so ClassInfo.isInitialized // is protected ci.setInitialized(); } } ti.getVM().notifyMethodExited(ti, this); }
public boolean isThreadEntry(ThreadInfo ti) { return (uniqueName.equals("run()V") && (ti.countStackFrames() == 1)); }