From: <zy...@us...> - 2009-07-11 06:47:51
|
Revision: 6527 http://jython.svn.sourceforge.net/jython/?rev=6527&view=rev Author: zyasoft Date: 2009-07-11 06:47:49 +0000 (Sat, 11 Jul 2009) Log Message: ----------- Added the ContextManager interface and supporting code to enable context mgmt through the with-statement to be efficiently inlined by the JVM. The ContextManager interface allows for direct calls via invokeinterface of __enter__ and __exit__ instead of requiring getattr. ContextGuard is used to wrap managers that don't support this Java interface. threading.Lock (=RLock) and Condition are now written in Java for performance and support the new ContextManager protocol. This addresses some of the performance issues that Tobias blogged on http://journal.thobe.org/2009/06/performance-of-synchronization.html Bumped bytecode magic. Modified Paths: -------------- trunk/jython/CoreExposed.includes trunk/jython/Lib/threading.py trunk/jython/src/org/python/compiler/CodeCompiler.java trunk/jython/src/org/python/core/imp.java trunk/jython/src/org/python/modules/Setup.java trunk/jython/src/org/python/modules/_collections/Collections.java trunk/jython/src/org/python/modules/_collections/PyDeque.java Added Paths: ----------- trunk/jython/src/org/python/core/ContextGuard.java trunk/jython/src/org/python/core/ContextManager.java trunk/jython/src/org/python/modules/_threading/ trunk/jython/src/org/python/modules/_threading/Condition.java trunk/jython/src/org/python/modules/_threading/Lock.java trunk/jython/src/org/python/modules/_threading/_threading.java Modified: trunk/jython/CoreExposed.includes =================================================================== --- trunk/jython/CoreExposed.includes 2009-07-09 01:47:52 UTC (rev 6526) +++ trunk/jython/CoreExposed.includes 2009-07-11 06:47:49 UTC (rev 6527) @@ -41,25 +41,27 @@ org/python/core/PyType.class org/python/core/PyUnicode.class org/python/core/PyXRange.class +org/python/modules/PyStruct.class +org/python/modules/PyTeeIterator.class org/python/modules/_codecs$EncodingMap.class +org/python/modules/_collections/PyDefaultDict.class +org/python/modules/_collections/PyDeque.class org/python/modules/_csv/PyDialect.class org/python/modules/_csv/PyReader.class org/python/modules/_csv/PyWriter.class org/python/modules/_functools/PyPartial.class +org/python/modules/_hashlib$Hash.class +org/python/modules/_threading/Condition.class +org/python/modules/_threading/Lock.class org/python/modules/_weakref/CallableProxyType.class +org/python/modules/_weakref/ProxyType.class org/python/modules/_weakref/ReferenceType.class -org/python/modules/_weakref/ProxyType.class -org/python/modules/_hashlib$Hash.class -org/python/modules/_collections/PyDefaultDict.class -org/python/modules/_collections/PyDeque.class org/python/modules/operator$PyAttrGetter.class org/python/modules/operator$PyItemGetter.class org/python/modules/random/PyRandom.class org/python/modules/thread/PyLocal.class org/python/modules/time/PyTimeTuple.class org/python/modules/zipimport/zipimporter.class -org/python/modules/PyStruct.class -org/python/modules/PyTeeIterator.class org/python/antlr/AST.class org/python/antlr/ast/alias.class org/python/antlr/ast/arguments.class Modified: trunk/jython/Lib/threading.py =================================================================== --- trunk/jython/Lib/threading.py 2009-07-09 01:47:52 UTC (rev 6526) +++ trunk/jython/Lib/threading.py 2009-07-11 06:47:49 UTC (rev 6527) @@ -5,6 +5,7 @@ from org.python.util import jython from thread import _newFunctionThread from thread import _local as local +from _threading import Lock, RLock, Condition import java.lang.Thread import weakref @@ -55,78 +56,7 @@ global _trace_hook _trace_hook = func -def RLock(*args, **kwargs): - return _RLock(*args, **kwargs) -class _RLock(object): - def __init__(self): - self._lock = ReentrantLock() - self.__owner = None - - def acquire(self, blocking=1): - if blocking: - self._lock.lock() - self.__owner = currentThread() - return True - else: - return self._lock.tryLock() - - def __enter__(self): - self.acquire() - return self - - def release(self): - assert self._lock.isHeldByCurrentThread(), \ - "release() of un-acquire()d lock" - self.__owner = None - self._lock.unlock() - - def __exit__(self, t, v, tb): - self.release() - - def locked(self): - return self._lock.isLocked() - - def _is_owned(self): - return self._lock.isHeldByCurrentThread() - -Lock = _RLock - -class Condition(object): - def __init__(self, lock=None): - if lock is None: - lock = RLock() - self._lock = lock - self._condition = lock._lock.newCondition() - - def acquire(self): - return self._lock.acquire() - - def __enter__(self): - self.acquire() - return self - - def release(self): - return self._lock.release() - - def __exit__(self, t, v, tb): - self.release() - - def wait(self, timeout=None): - if timeout: - return self._condition.awaitNanos(int(timeout * 1e9)) - else: - return self._condition.await() - - def notify(self): - return self._condition.signal() - - def notifyAll(self): - return self._condition.signalAll() - - def _is_owned(self): - return self._lock._lock.isHeldByCurrentThread() - class Semaphore(object): def __init__(self, value=1): if value < 0: Modified: trunk/jython/src/org/python/compiler/CodeCompiler.java =================================================================== --- trunk/jython/src/org/python/compiler/CodeCompiler.java 2009-07-09 01:47:52 UTC (rev 6526) +++ trunk/jython/src/org/python/compiler/CodeCompiler.java 2009-07-11 06:47:49 UTC (rev 6527) @@ -72,6 +72,8 @@ import org.python.antlr.base.mod; import org.python.antlr.base.stmt; import org.python.core.CompilerFlags; +import org.python.core.ContextGuard; +import org.python.core.ContextManager; import org.python.core.PyComplex; import org.python.core.PyFloat; import org.python.core.PyInteger; @@ -85,6 +87,7 @@ import org.objectweb.asm.Type; import org.objectweb.asm.commons.Method; + public class CodeCompiler extends Visitor implements Opcodes, ClassConstants //, PythonGrammarTreeConstants { @@ -324,10 +327,7 @@ public int makeArray(java.util.List<? extends PythonTree> nodes) throws Exception { // XXX: This should produce an array on the stack (if possible) instead of a local - // the caller is responsible for freeing. All callers are incorrectly freeing the - // array reference -- they do call freeLocal, but without nullifying the reference - // in the local. This is causing short term memory leaks - // (e.g. test_weakref.test_getweakrefs) + // the caller is responsible for freeing. int n; if (nodes == null) @@ -2276,24 +2276,24 @@ final Label label_catch = new Label(); final Label label_end = new Label(); - final Method getattr = Method.getMethod("org.python.core.PyObject __getattr__ (String)"); - final Method call = Method.getMethod("org.python.core.PyObject __call__ (org.python.core.ThreadState)"); - final Method call3 = Method.getMethod("org.python.core.PyObject __call__ (org.python.core.ThreadState,org.python.core.PyObject,org.python.core.PyObject,org.python.core.PyObject)"); + final Method contextGuard_getManager = Method.getMethod("org.python.core.ContextManager getManager (org.python.core.PyObject)"); + final Method __enter__ = Method.getMethod("org.python.core.PyObject __enter__ (org.python.core.ThreadState)"); + final Method __exit__ = Method.getMethod("boolean __exit__ (org.python.core.ThreadState,org.python.core.PyObject,org.python.core.PyObject,org.python.core.PyObject)"); // mgr = (EXPR) visit(node.getInternalContext_expr()); + + // wrap the manager with the ContextGuard (or get it directly if it supports the ContextManager interface) + code.invokestatic(Type.getType(ContextGuard.class).getInternalName(), contextGuard_getManager.getName(), contextGuard_getManager.getDescriptor()); code.dup(); - code.ldc("__exit__"); - code.invokevirtual(Type.getType(PyObject.class).getInternalName(), getattr.getName(), getattr.getDescriptor()); - final int __exit__ = code.getLocal("org/python/core/PyObject"); - code.astore(__exit__); + final int mgr_tmp = code.getLocal(Type.getType(ContextManager.class).getInternalName()); + code.astore(mgr_tmp); + // value = mgr.__enter__() - code.ldc("__enter__"); - code.invokevirtual(Type.getType(PyObject.class).getInternalName(), getattr.getName(), getattr.getDescriptor()); loadThreadState(); - code.invokevirtual(Type.getType(PyObject.class).getInternalName(), call.getName(), call.getDescriptor()); + code.invokeinterface(Type.getType(ContextManager.class).getInternalName(), __enter__.getName(), __enter__.getDescriptor()); int value_tmp = code.getLocal("org/python/core/PyObject"); code.astore(value_tmp); @@ -2311,13 +2311,12 @@ @Override public void finalBody(CodeCompiler compiler) throws Exception { - compiler.code.aload(__exit__); + compiler.code.aload(mgr_tmp); loadThreadState(); compiler.getNone(); compiler.code.dup(); compiler.code.dup(); - compiler.code.invokevirtual(Type.getType(PyObject.class).getInternalName(), - call3.getName(), call3.getDescriptor()); + compiler.code.invokeinterface(Type.getType(ContextManager.class).getInternalName(), __exit__.getName(), __exit__.getDescriptor()); compiler.code.pop(); } }; @@ -2364,7 +2363,7 @@ // # The exceptional case is handled here // exc = False # implicit // if not exit(*sys.exc_info()): - code.aload(__exit__); + code.aload(mgr_tmp); loadThreadState(); code.aload(ts_tmp); code.getfield("org/python/core/PyException", "type", $pyObj); @@ -2374,8 +2373,7 @@ code.freeLocal(ts_tmp); code.getfield("org/python/core/PyException", "traceback", "Lorg/python/core/PyTraceback;"); code.checkcast("org/python/core/PyObject"); - code.invokevirtual(Type.getType(PyObject.class).getInternalName(), call3.getName(), call3.getDescriptor()); - code.invokevirtual("org/python/core/PyObject", "__nonzero__", "()Z"); + code.invokeinterface(Type.getType(ContextManager.class).getInternalName(), __exit__.getName(), __exit__.getDescriptor()); code.ifne(label_end); // raise // # The exception is swallowed if exit() returns true @@ -2384,7 +2382,7 @@ code.athrow(); code.label(label_end); - code.freeLocal(__exit__); + code.freeLocal(mgr_tmp); handler.addExceptionHandlers(label_catch); return null; Added: trunk/jython/src/org/python/core/ContextGuard.java =================================================================== --- trunk/jython/src/org/python/core/ContextGuard.java (rev 0) +++ trunk/jython/src/org/python/core/ContextGuard.java 2009-07-11 06:47:49 UTC (rev 6527) @@ -0,0 +1,33 @@ +package org.python.core; + +/** Straightens the call path for some common cases + */ + +// XXX - add support for generators in conjunction w/ contextlib.contextmanager + +public class ContextGuard implements ContextManager { + + private final PyObject __enter__method; + private final PyObject __exit__method; + + private ContextGuard(PyObject manager) { + __enter__method = manager.__getattr__("__enter__"); + __exit__method = manager.__getattr__("__exit__"); + } + + public PyObject __enter__(ThreadState ts) { + return __enter__method.__call__(ts); + } + + public boolean __exit__(ThreadState ts, PyObject type, PyObject value, PyObject traceback) { + return __exit__method.__call__(ts, type, value, traceback).__nonzero__(); + } + + public static ContextManager getManager(PyObject manager) { + if (manager instanceof ContextManager) { + return (ContextManager) manager; + } else { + return new ContextGuard(manager); + } + } +} Added: trunk/jython/src/org/python/core/ContextManager.java =================================================================== --- trunk/jython/src/org/python/core/ContextManager.java (rev 0) +++ trunk/jython/src/org/python/core/ContextManager.java 2009-07-11 06:47:49 UTC (rev 6527) @@ -0,0 +1,11 @@ +package org.python.core; + +/** A <code>PyObject</code> that provides <code>__enter__</code> and <code>__exit__</code> methods for use in the with-statement. + * + * Implementing context managers can then be potentially inlined by the JVM. + */ + +public interface ContextManager { + public PyObject __enter__(ThreadState ts); + public boolean __exit__(ThreadState ts, PyObject type, PyObject value, PyObject traceback); +} Modified: trunk/jython/src/org/python/core/imp.java =================================================================== --- trunk/jython/src/org/python/core/imp.java 2009-07-09 01:47:52 UTC (rev 6526) +++ trunk/jython/src/org/python/core/imp.java 2009-07-11 06:47:49 UTC (rev 6527) @@ -20,7 +20,7 @@ private static final String UNKNOWN_SOURCEFILE = "<unknown>"; - private static final int APIVersion = 23; + private static final int APIVersion = 24; public static final int NO_MTIME = -1; Modified: trunk/jython/src/org/python/modules/Setup.java =================================================================== --- trunk/jython/src/org/python/modules/Setup.java 2009-07-09 01:47:52 UTC (rev 6526) +++ trunk/jython/src/org/python/modules/Setup.java 2009-07-11 06:47:49 UTC (rev 6527) @@ -55,6 +55,7 @@ "_csv:org.python.modules._csv._csv", "_systemrestart", "_ast:org.python.antlr.ast.AstModule", - "_marshal" + "_marshal", + "_threading:org.python.modules._threading._threading" }; } Modified: trunk/jython/src/org/python/modules/_collections/Collections.java =================================================================== --- trunk/jython/src/org/python/modules/_collections/Collections.java 2009-07-09 01:47:52 UTC (rev 6526) +++ trunk/jython/src/org/python/modules/_collections/Collections.java 2009-07-11 06:47:49 UTC (rev 6527) @@ -1,7 +1,6 @@ package org.python.modules._collections; import org.python.core.ClassDictInit; -import org.python.core.PyType; import org.python.core.PyObject; /** Modified: trunk/jython/src/org/python/modules/_collections/PyDeque.java =================================================================== --- trunk/jython/src/org/python/modules/_collections/PyDeque.java 2009-07-09 01:47:52 UTC (rev 6526) +++ trunk/jython/src/org/python/modules/_collections/PyDeque.java 2009-07-11 06:47:49 UTC (rev 6527) @@ -2,19 +2,11 @@ import org.python.core.PyIterator; import org.python.core.PyObject; -import org.python.core.PySequenceIter; import org.python.core.PyTuple; import org.python.core.PyType; import org.python.core.Py; import org.python.core.PyException; -import org.python.core.PyInteger; -import org.python.core.PyLong; -import org.python.core.PyNewWrapper; -import org.python.core.PyMethodDescr; import org.python.core.PyBuiltinCallable; -import org.python.core.PyBuiltinMethod; -import org.python.core.PyBuiltinMethodNarrow; -import org.python.core.PyString; import org.python.core.ThreadState; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; Added: trunk/jython/src/org/python/modules/_threading/Condition.java =================================================================== --- trunk/jython/src/org/python/modules/_threading/Condition.java (rev 0) +++ trunk/jython/src/org/python/modules/_threading/Condition.java 2009-07-11 06:47:49 UTC (rev 6527) @@ -0,0 +1,120 @@ +package org.python.modules._threading; + +import org.python.core.ContextManager; +import org.python.core.Py; +import org.python.core.PyNewWrapper; +import org.python.core.PyObject; +import org.python.core.PyType; +import org.python.core.ThreadState; +import org.python.expose.ExposedType; +import org.python.expose.ExposedMethod; +import org.python.expose.ExposedNew; + +@ExposedType(name = "_threading.Condition") +public class Condition extends PyObject implements ContextManager { + + public static final PyType TYPE = PyType.fromClass(Condition.class); + private final Lock _lock; + private final java.util.concurrent.locks.Condition _condition; + + public Condition() { + this(new Lock()); + } + + public Condition(Lock lock) { + _lock = lock; + _condition = lock._lock.newCondition(); + } + + @ExposedNew + final static PyObject Condition___new__ (PyNewWrapper new_, boolean init, + PyType subtype, PyObject[] args, String[] keywords) { + final int nargs = args.length; + if (nargs == 1) { + return new Condition((Lock)args[0]); + } + return new Condition(); + } + + public boolean acquire() { + return Condition_acquire(); + } + + @ExposedMethod + final boolean Condition_acquire() { + return _lock.acquire(); + } + + public PyObject __enter__(ThreadState ts) { + _lock.acquire(); + return this; + } + + @ExposedMethod + final PyObject Condition___enter__() { + Condition_acquire(); + return this; + } + + public void release() { + Condition_release(); + } + + @ExposedMethod + final void Condition_release() { + _lock.release(); + } + + public boolean __exit__(ThreadState ts, PyObject type, PyObject value, PyObject traceback) { + _lock.release(); + return false; + } + + @ExposedMethod + final boolean Condition___exit__(PyObject type, PyObject value, PyObject traceback) { + Condition_release(); + return false; + } + + public void wait$(PyObject timeout) throws InterruptedException { + Condition_wait(timeout); + } + + @ExposedMethod(defaults = "Py.None") + final void Condition_wait(PyObject timeout) throws InterruptedException { + if (timeout == Py.None) { + _condition.await(); + } else { + long nanos = (long) (timeout.__float__().asDouble() * 1e9); + _condition.awaitNanos(nanos); + } + } + + public void notify$() { + Condition_notify(); + } + + @ExposedMethod + final void Condition_notify() { + _condition.signal(); + } + + public void notifyAll$() { + Condition_notifyAll(); + } + + @ExposedMethod + final void Condition_notifyAll() { + _condition.signalAll(); + } + + public boolean _is_owned() { + return Condition__is_owned(); + } + + @ExposedMethod + final boolean Condition__is_owned() { + return _lock._lock.isHeldByCurrentThread(); + } +} + Added: trunk/jython/src/org/python/modules/_threading/Lock.java =================================================================== --- trunk/jython/src/org/python/modules/_threading/Lock.java (rev 0) +++ trunk/jython/src/org/python/modules/_threading/Lock.java 2009-07-11 06:47:49 UTC (rev 6527) @@ -0,0 +1,101 @@ +package org.python.modules._threading; + +import java.util.concurrent.locks.ReentrantLock; +import org.python.core.ContextManager; +import org.python.core.Py; +import org.python.core.PyNewWrapper; +import org.python.core.PyObject; +import org.python.core.PyType; +import org.python.core.ThreadState; +import org.python.expose.ExposedMethod; +import org.python.expose.ExposedNew; +import org.python.expose.ExposedType; + +@ExposedType(name = "_threading.Lock") +public class Lock extends PyObject implements ContextManager { + + public static final PyType TYPE = PyType.fromClass(Lock.class); + final ReentrantLock _lock; + + public Lock() { + _lock = new ReentrantLock(); + } + + @ExposedNew + final static PyObject Lock___new__ (PyNewWrapper new_, boolean init, + PyType subtype, PyObject[] args, String[] keywords) { + final int nargs = args.length; + return new Lock(); + } + + + @ExposedMethod(defaults = "true") + final boolean Lock_acquire(boolean blocking) { + if (blocking) { + _lock.lock(); + return true; + } else { + return _lock.tryLock(); + } + } + + public boolean acquire() { + return Lock_acquire(true); + } + + public boolean acquire(boolean blocking) { + return Lock_acquire(blocking); + } + + @ExposedMethod + final PyObject Lock___enter__() { + _lock.lock(); + return this; + } + + public PyObject __enter__(ThreadState ts) { + _lock.lock(); + return this; + } + + @ExposedMethod + final void Lock_release() { + if (!_lock.isHeldByCurrentThread()) { + throw Py.AssertionError("release() of un-acquire()d lock"); + } + _lock.unlock(); + } + + public void release() { + Lock_release(); + } + + @ExposedMethod + final boolean Lock___exit__(PyObject type, PyObject value, PyObject traceback) { + _lock.unlock(); + return false; + } + + public boolean __exit__(ThreadState ts, PyObject type, PyObject value, PyObject traceback) { + _lock.unlock(); + return false; + } + + @ExposedMethod + final boolean Lock_locked() { + return _lock.isLocked(); + } + + public boolean locked() { + return Lock_locked(); + } + + @ExposedMethod + final boolean Lock__is_owned() { + return _lock.isHeldByCurrentThread(); + } + + public boolean _is_owned() { + return Lock__is_owned(); + } +} Added: trunk/jython/src/org/python/modules/_threading/_threading.java =================================================================== --- trunk/jython/src/org/python/modules/_threading/_threading.java (rev 0) +++ trunk/jython/src/org/python/modules/_threading/_threading.java 2009-07-11 06:47:49 UTC (rev 6527) @@ -0,0 +1,15 @@ +package org.python.modules._threading; + +import org.python.core.ClassDictInit; +import org.python.core.Py; +import org.python.core.PyObject; + +public class _threading implements ClassDictInit { + + public static void classDictInit(PyObject dict) { + dict.__setitem__("__name__", Py.newString("_threading")); + dict.__setitem__("Lock", Lock.TYPE); + dict.__setitem__("RLock", Lock.TYPE); + dict.__setitem__("Condition", Condition.TYPE); + } +} This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |