Issue #19722: Added opcode.stack_effect(), which accurately
computes the stack effect of bytecode instructions.
diff --git a/Lib/opcode.py b/Lib/opcode.py
index 78d1229..0bd1ee6 100644
--- a/Lib/opcode.py
+++ b/Lib/opcode.py
@@ -8,6 +8,19 @@
            "haslocal", "hascompare", "hasfree", "opname", "opmap",
            "HAVE_ARGUMENT", "EXTENDED_ARG", "hasnargs"]
 
+# It's a chicken-and-egg I'm afraid:
+# We're imported before _opcode's made.
+# With exception unheeded
+# (stack_effect is not needed)
+# Both our chickens and eggs are allayed.
+#     --Larry Hastings, 2013/11/23
+
+try:
+    from _opcode import stack_effect
+    __all__.append('stack_effect')
+except ImportError:
+    pass
+
 cmp_op = ('<', '<=', '==', '!=', '>', '>=', 'in', 'not in', 'is',
         'is not', 'exception match', 'BAD')
 
diff --git a/Lib/test/test__opcode.py b/Lib/test/test__opcode.py
new file mode 100644
index 0000000..cab8769
--- /dev/null
+++ b/Lib/test/test__opcode.py
@@ -0,0 +1,22 @@
+import dis
+import _opcode
+from test.support import run_unittest
+import unittest
+
+class OpcodeTests(unittest.TestCase):
+
+    def test_stack_effect(self):
+        self.assertEqual(_opcode.stack_effect(dis.opmap['POP_TOP']), -1)
+        self.assertEqual(_opcode.stack_effect(dis.opmap['DUP_TOP_TWO']), 2)
+        self.assertEqual(_opcode.stack_effect(dis.opmap['BUILD_SLICE'], 0), -1)
+        self.assertEqual(_opcode.stack_effect(dis.opmap['BUILD_SLICE'], 1), -1)
+        self.assertEqual(_opcode.stack_effect(dis.opmap['BUILD_SLICE'], 3), -2)
+        self.assertRaises(ValueError, _opcode.stack_effect, 30000)
+        self.assertRaises(ValueError, _opcode.stack_effect, dis.opmap['BUILD_SLICE'])
+        self.assertRaises(ValueError, _opcode.stack_effect, dis.opmap['POP_TOP'], 0)
+
+def test_main():
+    run_unittest(OpcodeTests)
+
+if __name__ == "__main__":
+    test_main()